这题的意思:给你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;
}