Codeforces 400D Dima and Bacteria(并查集最短路)

题意:有n个k种细菌,每种细菌有ci个,各自标号为
细菌之间(注意这里非种类之间)有m种转换关系,即u和v可相互转换,代价为x。
若每种细菌内部可两两转换且代价为0,输出Yes,并且用矩阵输入各种类之间最小转换代价,不能转换的输出-1。
否则输出No。
思路:
1、判断每种细菌内部可否两两转换且代价为0,可用并查集,对0边的两个细菌合并,最后判断每种细菌内部是否有共同祖先。
2、各种类之间最小转换代价则用Floyd。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #define N 100005
  4 #define M 505
  5 #define INF 99999999
  6 
  7 int fa[N], rank[N], vis[N];
  8 int a[M][M], c[M], up[M], down[M];
  9 
 10 void Floyd(int n) {
 11     for (int k = 1; k <= n; k++) {
 12         for (int i = 1; i <= n; i++) {
 13             for (int j = 1; j <= n; j++) {
 14                 if((a[i][k] != INF) && (a[k][j] != INF)
 15                     &&(a[i][j] > a[i][k] + a[k][j] || a[i][j] == INF)) {
 16                         a[i][j] = a[i][k] + a[k][j];
 17                 }
 18             }
 19         }
 20     }
 21 }
 22 
 23 
 24 void Make_set(int n)
 25 {
 26     for(int i=1; i<=n; i++)
 27     {
 28         fa[i] = i;
 29         rank[i] = 0;
 30     }
 31 }
 32 int find(int x)//查找元素所在的父节点,回溯时压缩路径
 33 {
 34     if(x!=fa[x])
 35         fa[x]=find(fa[x]);
 36     return fa[x];
 37 }
 38 void Union(int x,int y)//按秩合并x,y所在的集合
 39 {
 40     x=find(x);
 41     y=find(y);
 42     if(x==y) return ;
 43     if(rank[x]>rank[y])
 44         fa[y]=x;
 45     else if(rank[x]<rank[y])
 46         fa[x]=y;
 47     else {
 48         rank[x]++;
 49         fa[y]=x;
 50     }
 51 }
 52 
 53 int main()
 54 {
 55     int n, m, k;
 56     scanf("%d%d%d",&n,&m,&k);
 57     Make_set(n);
 58     for(int i=1; i<=k; i++)
 59         scanf("%d",&c[i]);
 60     int tmp = 0;
 61     for(int i=1; i<=k; i++)
 62     {
 63         up[i] = tmp + 1;
 64         down[i] = tmp + c[i];
 65         tmp += c[i];
 66         for(int j=up[i]; j<=down[i]; j++) vis[j] = i;
 67     }
 68     for(int i=1; i<=k; i++)
 69         for(int j=i; j<=k; j++)
 70             a[i][j] = a[j][i] = INF;
 71 
 72     int x, y, d;
 73     for(int i=1; i<=m; i++)
 74     {
 75         scanf("%d%d%d",&x,&y,&d);
 76         int ta = vis[x], tb = vis[y];
 77         if(d==0//0边均
 78             Union(x, y);
 79         if(ta!=tb)
 80         {
 81             if(d<a[ta][tb])
 82                 a[ta][tb] = a[tb][ta] = d;
 83 
 84         }
 85     }
 86 
 87     int flag = 0;
 88     for(int i=1; i<=k; i++)
 89     {
 90         int flag1 = 0;
 91         int tmp = find(up[i]);
 92         for(int j=up[i]+1; j<=down[i]; j++)
 93         {
 94             if(find(j)!=tmp)
 95             {
 96                 flag1 = 1;
 97                 break;
 98             }
 99         }
100         if(flag1 == 1)
101         {
102             flag=1;
103             break;
104         }
105     }
106     if(flag==0)
107     {
108         Floyd(k);
109         printf("Yes\n");
110         for(int i=1; i<=k; i++)
111         {
112             for(int j=1; j<=k; j++)
113             {
114                 if(i==j) printf("");
115                 else if(a[i][j]==INF) printf("-1 ");
116                 else
117                     printf("%d ",a[i][j]);
118             }
119             printf("\n");
120         }
121     }
122     else
123         printf("No\n");
124 
125     return 0;
126 }
View Code

posted @ 2014-03-21 19:41  byluoluo  阅读(296)  评论(0编辑  收藏  举报