题意:英文实在不行,大概描述一下,第一行给定n,m,k个集合(其实是k种细菌)。n代表n个点。(其实是n个细菌。)并且1到n编号。第二行给出k个集合的点数量。(其实是k种细菌的数量)。下面m行,给出m条边(其实是m种仪器。。)给出u,v,x代表编号为u的点(细菌),到编号为v的点,需要花费x的能量。
问的是是否满足同种细菌移动的能量为0。如果满足的话,输出一个k*k行的矩阵,代表不同集合(细菌)的点之间互相移动所需要最小的花费。
假如有一个集合无法到达另一个集合,输出-1.
题目实在是太抽象了。。。
简述,就是给你n个点,m条边。K个集合,k个集合的点数,满足每个集合任意两点之间移动所需要的花费为0。求的是任意两个集合移动所需要的花费。
思路:先给每个集合的点编号。然后存入图里面。然后用并查集判断是否满足同个集合任意两点距离为0。(相当于所有的点他们的关系构成一个集合)。
如果满足的话,接下来floyd 求传递闭包,算出任意两个集合的点移动所需要的花费,如果不能到达,令其值为负一。
注意:n,m的范围很大,输入要用long long or __int64。
上代码
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <cstring> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #define N 100005 #define M 505 #define maxn 100005 #define MAXN 200005 #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 typedef long long ll; using namespace std; ll n,m,k; ll fa[N]; ll num[N]; ll belong[N]; ll mpt[M][M]; ll find(ll x) //查找 { if(x!=fa[x]) fa[x]=find(fa[x]); return fa[x]; } void hebing(ll x,ll y) //并查集 { x=find(x); y=find(y); fa[y]=x; } bool judge() { ll i,j,p; p=1; for(i=1; i<=k; i++) { int x=find(p); for(j=1; j<=num[i]; j++) if(find(p++)!=x) return 0; } //用并查集判断一个集合内的任意两点是否花费为0。 return 1; } void floyd() //floyd 算法求传递闭包。用边联通所有有关系的点,并且算出任意两点的最短距离 { for(ll p=1; p<=k; p++) { for(ll i=1; i<=k; i++) { for(ll j=1; j<=k; j++) { mpt[i][j]=min(mpt[i][j],mpt[i][p]+mpt[p][j]); } } } } int main() { ll i,j,p; while(scanf("%lld%lld%lld",&n,&m,&k)!=EOF) { memset(mpt,INF,sizeof(mpt)); for(i=1; i<=k; i++) for(j=1; j<=k; j++) { if(i==j) mpt[i][j]=mpt[j][i]=0; else mpt[i][j]=mpt[j][i]=INF; //初始化不同集合的边。 } for(i=1; i<=n; i++) fa[i]=i; //并查集的初始化 p=1; for(i=1; i<=k; i++) { scanf("%lld",&num[i]); //一个集合 for(j=1; j<=num[i]; j++) belong[p++]=i; //给每个集合的每个点编号 } ll u,v,w,uu,vv; while(m--) { scanf("%lld%lld%lld",&u,&v,&w); if(!w) hebing(u,v); //花费为0就合并。。 uu=belong[u]; //把编号存入图里 vv=belong[v]; //同上 mpt[uu][vv]=mpt[vv][uu]=min(mpt[uu][vv],w); } if(!judge()) { printf("No\n"); //判断是否满足 continue; } printf("Yes\n"); floyd(); for(i=1; i<=k; i++) { for(j=1; j<=k; j++) //枚举所有的不同集合 { if(i==j) mpt[i][j]=0; if(mpt[i][j]==INF) //不能到达 mpt[i][j]=-1; //令为负一 if(j<k) printf("%lld ",mpt[i][j]); else printf("%lld",mpt[i][j]); } printf("\n"); } } return 0; }
CodeForces 400D (最短路+并查集) Dima and Bacteria
原文:http://blog.csdn.net/sky_miange/article/details/44497585