Uva12118——Inspector's Dilemma

这题的意思:给你V个城市,两两城市有双向的通路,给你E个边,求最短路径走过这E个边。边长为T。

一开始以为是BFS来求解,但是怎么都想不到切入口。后面看到欧拉两个字,恍然大悟,这题就是无向图的欧拉回路的求解。只不过,还需要判断图是否连通,存在多个连通图,需要将他们连通起来。然后判断各个节点的度,奇数的节点大于2,则需要加上 奇数点 / 2 - 1个边,才能使图存在欧拉回路。


下面的代码,有注释:


#include <iostream>
#include <cstring>
using namespace std;

int num[1010];
int pre[1010];

int finds(int x)    //并查集判断图连通性
{
	int r = x;
	while(pre[r] != r)
		r = pre[r];

	int i = x, j;
	while(i != r)
	{
		j = pre[i];
		pre[i] = r;
		i = j;
	}
	return r;
}

void join(int x, int y)
{
	int fx = finds(x);
	int fy = finds(y);
	if(fx != fy)
		pre[fy] = pre[fx];
}

int main()
{
//	freopen("1.txt", "r", stdin);
	int v, e, t, n = 0, i, a, b;
	while(cin >> v >> e >> t)
	{
		if(v == 0 && e == 0 && t == 0)
			break;

		memset(num, 0, sizeof(num));   //初始化
		for(i = 0; i < v + 5; i++)
			pre[i] = i;
		for(i = 0; i < e; i++)         //输入
		{
			cin >> a >> b;
			join(a, b);
			num[a]++; num[b]++;
		}
		
		int a = 0, b = 0;            //a 为 第一个连通图,b为剩下的连通图
		for(i = 1; i <= v; i++)
		{
			if(num[i] && pre[i] == i)   
			{
				if(!a)
					a = i;
				else       //找到多个连通图
				{
					b = i;

					int j = 1;
					while(true)     //查找a连通图 的 奇数点为 j
					{
						if(a == finds(j) && num[j] % 2)
							break;
						j++;
						if(j > v)
							break;
					}
					int k = 1;
					while(true)      //查找b连通图 的 奇数点 为 k
					{
						if(b == finds(k) && num[k] % 2)
							break;
						k++;
						if(k > v)
							break;
					}
					if(j > v)   //如果不存在奇数点,随便找个偶数点
					{
						j = 1;
						while(true)
						{
							if(a == finds(j) && num[j] % 2 == 0)
								break;
							j++;
						}
					}
					if(k > v)  //同上
					{
						k = 1;
						while(true)
						{
							if(b == finds(k) && num[k] % 2 == 0)
								break;
							k++;
						}
					}
					num[j]++; num[k]++;   //合并起来
					pre[b] = a;
					e++; //边数加1
				}
			}
		}

		int c = 0;
		for(i = 1; i <= v; i++)   //找奇数点
		{
			if(num[i] % 2)
				c++;
		}
		if(c > 2)   //加上 奇数点 数 / 2 - 1个边,使得存在欧拉回路
			e += (c / 2 - 1);

		cout << "Case " << ++n << ": " << e * t << endl;
	}
	return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值