一、题意
有n个城市,m条道路,每条道路收费t元。
之后m行每行两个点表示一条道路。
要求你找到一条最短路径,使得该路径经过所有这m条道路。
输出路径的收费之和。
二、解析
别以为这是一道最短路或并查集问题,实际上这是一道欧拉回路问题。
那m条道路连接后,将会分成几个连通分量。每个连通分量需要统计其中奇数点的个数(通过一次dfs即可),然后先在这些连通分量内部加边来使之可以一笔画,然后再加边把所有连通分量连接起来。
需要注意的点:
- 连通分量可能只有一个点
- 有些城市可能压根就不参与,因此需要一个need[maxn]进行标记。
- m=0的情形
三、代码
#include <iostream> #include <vector> using namespace std; const int maxn = 1000 + 5; vector<int> G[maxn]; int n, m, t, kase = 1, vis[maxn], need[maxn]; int dfs(int u) { int res = G[u].size() % 2; vis[u] = 1; for(int v : G[u]) if(!vis[v]) { res += dfs(v); } return res; } int main() { while(cin >> n >> m >> t && n) { for(int i = 1; i <= n; i ++) G[i].clear(); fill(need, need + n + 1, 0); for(int i = 0; i < m; i ++) { int u, v; cin >> u >> v; G[u].push_back(v); G[v].push_back(u); need[u] = need[v] = 1; } fill(vis, vis + n + 1, 0); int ans = m, block_num = 0; for(int i = 1; i <= n; i ++) if(need[i] && !vis[i]) { int res = dfs(i); ans += (res > 1 ? (res - 2) / 2 : 0); block_num ++; } ans += block_num - 1; if(m == 0) ans = 0; cout << "Case " << kase ++ << ": " << ans * t << endl; } }
四、归纳
- 欧拉回路:如果一个无向图是联通的,那么它最多只有两个奇点(一出一进)
- 做题时多留心取值返回,比如这题m是可以等于0的