題目鏈接: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;
}