题意:有一个n个点的无向完全图,找一条最短路(起点终点任意),使得该道路经过E条指定的边。
分析:
1、因为要使走过的路最短,所以每个指定的边最好只走一遍,所以是欧拉道路。
2、若当前连通的道路不是欧拉道路,最好的方法是通过加边使其成为欧拉道路。
3、若该图连通,则度数为奇数的点的个数只会是偶数个(连通图性质)。
4、欧拉道路只有两个度数为奇数的点,其他点度数均为偶数。
5、使一个连通图变为欧拉道路,只需要在所有度数为奇数的点之间加边,若一个连通图度数为奇数的点有x个,则需要加边(x - 2) / 2。
6、给定的边可能组成了几个连通图(并查集判断连通图个数),将各个连通图都变成欧拉道路后,再依次连接各欧拉道路,使整个图连通,依次连接各欧拉道路的加边数为欧拉道路总数-1。
7、最后便忘了加上指定的E条边的长度。
8、注意如果没有指定边,最短路长度为0。
#pragma comment(linker, "/STACK:102400000, 102400000") #include<cstdio> #include<cstring> #include<cstdlib> #include<cctype> #include<cmath> #include<iostream> #include<sstream> #include<iterator> #include<algorithm> #include<string> #include<vector> #include<set> #include<map> #include<stack> #include<deque> #include<queue> #include<list> #define Min(a, b) ((a < b) ? a : b) #define Max(a, b) ((a < b) ? b : a) typedef long long ll; typedef unsigned long long llu; const int INT_INF = 0x3f3f3f3f; const int INT_M_INF = 0x7f7f7f7f; const ll LL_INF = 0x3f3f3f3f3f3f3f3f; const ll LL_M_INF = 0x7f7f7f7f7f7f7f7f; const int dr[] = {0, 1}; const int dc[] = {1, 0}; const int MOD = 1e9 + 7; const double pi = acos(-1.0); const double eps = 1e-8; const int MAXN = 1000 + 10; const int MAXT = 500 + 10; using namespace std; int fa[MAXN]; int V, E, T; int e[MAXN]; set<int> v[MAXN];//每个点的度数 set<int> cnt; void init(){ for(int i = 1; i <= V; ++i){ fa[i] = i; v[i].clear(); } memset(e, 0, sizeof e); cnt.clear(); } int Find(int v){ return fa[v] = (fa[v] == v) ? v : Find(fa[v]); } int solve(){ if(E == 0) return 0;//如果没有指定边,最短路长度为0 for(int i = 1; i <= V; ++i){ int len = v[i].size(); if(len == 0) continue; int f = Find(i); cnt.insert(f); if(len & 1){ ++e[f]; } } int ans = 0; for(int i = 1; i <= V; ++i){ if(e[i]){ ans += (e[i] - 2) / 2; } } return (ans + (int)cnt.size() - 1 + E) * T; } int main(){ int kase = 0; while(scanf("%d%d%d", &V, &E, &T) == 3){ if(!V && !E && !T) return 0; init(); for(int i = 0; i < E; ++i){ int x, y; scanf("%d%d", &x, &y); v[x].insert(y); v[y].insert(x); int tx = Find(x); int ty = Find(y); if(tx < ty) fa[ty] = tx; else if(tx > ty) fa[tx] = ty; } printf("Case %d: %d\n", ++kase, solve()); } return 0; }