codeforces 400D - Dima and Bacteria

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章