题目链接:http://codeforces.com/problemset/problem/400/D
题目大意:n个培养基,m种仪器,分成k种,每种细菌数量c[i],然后就给出从第i到第j个培养基转化需要的花费。判断同种培养基之间的转化是不是都是可以0花费,如果可以再输出不同种培养基之间转化的最小花费。
如果有疑惑的话,再以样例解释一下——
4 4 2
1 3
2 3 0
3 4 0
2 4 1
2 1 2
_____
Yes
0 2
2 0
4个培养皿,4种转换路径,分成2种,第一种细菌的数量为1,第二种的细菌数量为3,即1号培养皿为种类①,2、3、4号培养皿为种类②;
2号培养皿<->3号培养皿=0花费
3号培养皿<->4号培养皿=0花费
2号培养皿<->4号培养皿=1花费
2号培养皿<->1号培养皿=2花费
因此同种培养皿可以0花费相互转换,两个集合间的转换的最小花费为2。
题目分析:关于同种培养皿之间是否可以互相转换,我们用并查集将花费为0的两个点加入一个集合;而判断yes or no的时候我们就看一下同一种类的点是不是已经在一个集合了;最后的最短路就用floyd计算了。
代码参考:
#include<set>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 9;
int c[N];
struct Node
{
int u, v, x;
} Edge[N];
int p[N];
int find(int x)
{
return p[x] < 0 ? x : p[x] = find(p[x]);
}
void un(int a, int b)
{
int x = find(a), y = find(b);
if (x != y)
{
p[x] = y;
}
}
int sum[N];
int dis[555][555];
int id[N];
void checkMin(int & a, int b)
{
if (a > b)
{
a = b;
}
}
const int INF = 1e9;
int main()
{
int n, m, k, i, j;
while (~scanf("%d%d%d", &n, &m, &k))
{
memset(p, -1, sizeof(p));
for (i = 1; i <= k; ++i)
{
for (j = 1; j <= k; ++j)
{
dis[i][j] = INF;
}
dis[i][i] = 0;
}
sum[0] = 0;
for (i = 1; i <= k; ++i)
{
scanf("%d", &c[i]);
sum[i] = sum[i - 1] + c[i];//sum[i]代表前i种的总数量,sum[1]=c[1] ,sum[2]=c[1]+c[2]
for (j = sum[i - 1] + 1; j <= sum[i]; ++j)
{
id[j] = i;//1~c[1]染成颜色0, c[1]+1~c[2]染成颜色1
}
}
for (i = 0; i < m; ++i)
{
scanf("%d%d%d", &Edge[i].u, &Edge[i].v, &Edge[i].x);
int a = Edge[i].u, b = Edge[i].v, c = Edge[i].x;
if (Edge[i].x == 0)//如果当前仪器x为0,就将两个序号的细菌连接连接(并查集)
{
un(Edge[i].u, Edge[i].v);
}
//种类之间的最小花费预处理
checkMin(dis[id[a]][id[b]], c);
checkMin(dis[id[b]][id[a]], c);
}
bool zeroDis = true;
for (i = 1; i <= k; ++i)
{
for (j = sum[i - 1] + 2; j <= sum[i]; ++j)
{
if (find(j) != find(sum[i - 1] + 1))//如果sum[i-1]+1与sum[i-1]+2,sum[i-1]+3,……,其中有一个的root不一样的话则不正确
{
zeroDis = false;
}
}
}
if (!zeroDis)
{
puts("No");
continue;
}
int t;
//floyd
for (t = 1; t <= k; ++t)
{
for (i = 1; i <= k; ++i)
{
for (j = 1; j <= k; ++j)
{
checkMin(dis[i][j], dis[i][t] + dis[t][j]);
}
}
}
puts("Yes");
for (i = 1; i <= k; ++i)
{
for (j = 1; j <= k; ++j)
{
if (dis[i][j] == INF)
{
dis[i][j] = -1;
}
printf("%d ", dis[i][j]);
}
puts("");
}
}
return 0;
}