题目大意:
有一个有V(V<=1000)个节点的图,每两个点之间都有边连接,所有边长为T。先给出E条指定的边,找出一条最短路(起点终点随意),使这条路径经过所有给定的边。
题目链接:https://vjudge.net/problem/UVA-12118
思路:
一开始想错了,简单的记录每个数字出现的次数,把出现奇数的点作为欧拉道路的奇点,设有n个这样的点,那么在原来的道路基础上,再加(n-1)/2条路,但是发现是错误的。
比如下面这组数据,
6 6 1
1 2
1 3
2 3
4 5
4 6
5 6
这里面没有我说的奇点,但是并不联通,所以终于明白错误的地方,首先当做一个又一个连通的子图,把子图构造成欧拉道路(子图的奇点小于等于2),算出子图的奇点数目x,加上(x - 1) / 2 条路,最后将每个子图都连起来,有n个子图就加n - 1条路,最后得结果。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
bool num[1100];
bool Map[1010][1010];
vector<int>node;
bool vis[1100];
ll v, e, t, tot;
void dfs(int n)
{
vis[n] = 1;
if(num[n])tot++;
for(int i = 1; i <= v; i++)
{
if(Map[n][i] && !vis[i])dfs(i);
}
}
int main()
{
//freopen("out.txt","r",stdin);
ll cases = 0;
while(cin >> v >> e >> t)
{
if(!v && !e && !t)break;
ll a, b;
memset(num, 0, sizeof(num));
memset(Map, 0, sizeof(Map));
memset(vis, 0, sizeof(vis));
node.clear();
for(ll i = 0; i < e; i++)
{
cin >> a >> b;
num[a] = !num[a];//首先判断是否是奇点,用这个为1表示是奇点,为0则不是
num[b] = !num[b];
Map[a][b] = Map[b][a] = 1;
node.push_back(a);//用到的点直接存起来
node.push_back(b);
}
ll ans = 0, n = 0;
for(vector<int>::iterator it = node.begin(); it != node.end(); it++)
{
if(!vis[*it])//如果该点还未经过,dfs这个点,把可到达的地方全部走一遍,判断子图里面奇点的数目
{
tot = 0;
dfs(*it);
ans += (tot - 1) / 2;//把该子图变成欧拉道路所加的路
n++;//子图的数目
}
}
ans += e;//最开始的道路
if(n > 1)ans += n - 1;//连接子图的路(大于一是因为可能会为0,因为e可能为0)
cout<<"Case "<<++cases<<": "<<ans * t<<endl;
}
}