一、题意
有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的

京公网安备 11010502036488号