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;
}


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