题意:给定n个点,e条边和每条边的长度t,每两个点之间都有路相连,让你求一条最短的路经过这e条边。
析:刚开始想到要判连通,然后把相应的几块加起来,但是,第二个样例就不过,后来一想,那么有欧拉回路的还得加1啊。
又想每次再判一次是不是欧拉回路,怎么判又是问题,因为并不知道哪些是连在一块的,还得再查找,麻烦啊。。。。
后来上网看了一下题解,原来是要构造啊,也就是说把每个连通块都构造成一个欧拉回路,那么再减去端点的,就能完全连通了。
真是好方法,欧拉回路满足每个点的度都是偶数,也就是说如果不是偶数那么我们就人为的给加上一条,最后计算我们加了多少条,
然后再加上原来题目的e条,就是最后的条数。
代码如下:
#include <iostream> #include <cstdio> #include <vector> #include <cstring> using namespace std; const int maxn = 1000 + 10; int t, n, e; vector<int> G[maxn]; bool vis[maxn]; int dfs(int u){ if(vis[u]) return 0; vis[u] = true; int ans = (G[u].size() & 1); for(int i = 0; i < G[u].size(); ++i) ans += dfs(G[u][i]); return ans; } int solve(){ int ans = 0; for(int i = 1; i <= n; ++i) if(!G[i].empty() && !vis[i]) ans += max(dfs(i), 2); return max((ans-2) / 2, 0) + e; } int main(){ // freopen("in.txt", "r", stdin); int kase = 0; while(scanf("%d %d %d", &n, &e, &t) == 3){ if(!n && !e && !t) break; int u, v; for(int i = 1; i <= n; ++i) G[i].clear(); memset(vis, 0, sizeof(vis)); for(int i = 0; i < e; ++i){ scanf("%d %d", &u, &v); G[u].push_back(v); G[v].push_back(u); } printf("Case %d: %d\n", ++kase, t * solve()); } return 0; }