天天看點

zoj 3396 斯坦那樹

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4004

題意:給你一副圖,求使得給定三個點連通的最小代價,大概就這樣,具體看題目吧

斯坦那樹有一個結論:n個點的斯坦那樹至少會經過n-2個中間節點,這裡n=3,是以至少會經過一個中間節點,求出這三個點的單源最短路後枚舉中間節點即可。

把m寫成n,WA了數遍,實在是太水了

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int inf = 0x7fffffff / 3;

const int maxn = 510;
int dis1[maxn],dis2[maxn],dis3[maxn];
vector<pair<int,int> > edge[maxn];
bool vis[maxn];
int n,m;
void spfa(int s,int dis[],int n) 
{
	memset(vis,false,sizeof(vis));
	fill(dis,dis+n+1,-1);
	dis[s]=0;
	queue<int> Q;Q.push(s);
	while(!Q.empty()){
		int fr=Q.front();Q.pop();
		vis[fr]=false;
		for(int i=0;i<edge[fr].size();i++)
		{
			int v=edge[fr][i].first,w=edge[fr][i].second;
			if(dis[v]==-1 || dis[v]>dis[fr]+w)
			{
				dis[v]=dis[fr]+w;
				if(!vis[v])
				{
					vis[v]=true;
					Q.push(v);
				}
			}
		}
	}
}

void Min(int &a,int b){
	if(a==-1 || b<a) a=b;
}
int t[10010];
int main()
{
	int L,q,ca=1;
	while(scanf("%d%d%d",&n,&m,&L)!=EOF)
	{
		for(int i=1;i<=m;i++)  edge[i].clear();
		for(int i=1;i<=n;i++)  scanf("%d",&t[i]);
		int a,b,c;
		for(int i=1;i<=L;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			edge[a].push_back(make_pair(b,c));
			edge[b].push_back(make_pair(a,c));
		}
		printf("Case #%d\n",ca++);
		scanf("%d",&q);
		for(int k=1;k<=q;k++)
		{
			scanf("%d%d%d",&a,&b,&c);
			a=t[a];b=t[b];c=t[c];
			spfa(a,dis1,m);
			spfa(b,dis2,m);
			spfa(c,dis3,m);
			int ans=-1;
			for(int i=1;i<=m;i++)
			{
				if(dis1[i]==-1 || dis2[i]==-1 || dis3[i]==-1) continue;
				Min(ans,dis1[i]+dis2[i]+dis3[i]);
			}
			printf("Line %d: ",k);
			if(ans==-1) puts("Impossible to connect!");
			else printf("The minimum cost for this line is %d.\n",ans);
		}
	}
	return 0;
}