Codeforces 400D Dima and Bacteria(并查集最短路)
2014-03-21 19:41
288 查看
题意:有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
, rank
, vis
;
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 }
if(flag1 == 1)
{
flag=1;
break;
}
}
if(flag==0)
{
Floyd(k);
printf("Yes\n");
for(int i=1; i<=k; i++)
{
for(int j=1; j<=k; j++)
{
if(i==j) printf("0 ");
else if(a[i][j]==INF) printf("-1 ");
else
printf("%d ",a[i][j]);
}
printf("\n");
}
}
else
printf("No\n");
return 0;
}View Code
细菌之间(注意这里非种类之间)有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
, rank
, vis
;
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 }
if(flag1 == 1)
{
flag=1;
break;
}
}
if(flag==0)
{
Floyd(k);
printf("Yes\n");
for(int i=1; i<=k; i++)
{
for(int j=1; j<=k; j++)
{
if(i==j) printf("0 ");
else if(a[i][j]==INF) printf("-1 ");
else
printf("%d ",a[i][j]);
}
printf("\n");
}
}
else
printf("No\n");
return 0;
}View Code
相关文章推荐
- Codeforces 400D. Dima and Bacteria【并查集+最短路】
- Codeforces 400D Dima and Bacteria 【并查集 + 最短路】
- ACM学习历程—CodeForces 601A The Two Routes(最短路)
- CodeForces 123A 并查集
- Codeforces 667D World Tour 最短路
- A - Cthulhu CodeForces - 103B (并查集)
- [Codeforces 325 D. Reclamation]并查集
- Codeforces 9E Interesting Graph and Apples(并查集)
- codeforces 468B two set(并查集)
- [欧拉回路 并查集] Codeforces 547D #305 (Div. 1) D. Mike and Fish
- codeforces 757F - 最短路DAG+灭绝树
- CodeForces 449B - Jzzhu and Cities(最短路)
- bzoj3694 最短路 并查集(树链剖分)
- 洛谷P4768 [NOI2018]归程(可持久化并查集,最短路)
- FJUT 3104 海平面上升 最短路 或者 离线+并查集
- 【打CF,学算法——四星级】CodeForces 455C Civilization (【详解】并查集+树的直径)
- CodeForces - 744A (并查集)
- codeforces 892E(离散化+可撤销并查集)
- codeforces 722C 并查集好题+逆序处理
- codeforces 731C (并查集 水)