FZU|FZU - 2112 Tickets (欧拉回路+联通块判断)
题目链接: https://cn.vjudge.net/problem/FZU-2112
题目大意: 给定一个图的N个边,求添加最少的边使这个图形成欧拉路。不必所有的点都联通,只需要把已给出的边形成欧拉路。
解题过程: 之前好像做过一次做过题,然后又看到了,当时也忘记在哪看到了,不知道A了没有,反正记得看题解没理解……
这道题刚开始理解错了,还以为是求哈密顿图,这个是真的不会。回来又看了一遍题意才发现是之前做过的欧拉路。
然后又仔细想了下,可算是想通了。
题目分析: 首先BFS一遍记录下联通块个数, 每个联通块奇点的个数。
要构成欧拉路,就要把这些联通块之前用一条边连起来。
假设N个联通块,那么需要N-1个边把他们连接起来。
然后对于每一个联通块,如果奇点个数大于2,那么每多了个奇点,需要花费一条边连起来这两个奇点。
可以证明,对于任意一个无向图,他奇点的个数一定是偶数个。对于每无向边那么一定会给两个点增加一个度,所以奇点的个数一定是偶数个的。
AC代码:
#include
#include
#include
using namespace std;
const int MAX = 112345;
int n, m;
int vis[MAX];
int book[MAX];
vector edge[MAX];
//Dfs判断联通块个数和统计奇点的个数
void dfs(int u, int& odd) {
if (edge[u].size()%2)
odd++;
vis[u] = 1;
for (int i = 0;
i < edge[u].size();
i++) {
int v = edge[u][i];
if (!vis[v])
dfs(v, odd);
}
}int solve() {
int cnt = 0;
for (int i = 1;
i <= n;
i++) {
if (vis[i] || !book[i])
continue;
int odd = 0;
dfs(i, odd);
//每个联通块的奇点如果大于2那么应该给做过联通块添加边消去奇点
cnt += odd > 2 ? (odd-2)/2:0;
cnt++;
}
printf("%d\n", cnt-1);
}int main() {
int T;
scanf("%d", &T);
while (T--) {scanf("%d %d", &n, &m);
memset(vis, 0, sizeof(vis));
memset(book, 0, sizeof(book));
for (int i = 0;
i <= n;
i++) {
edge[i].clear();
}for (int i = 0;
i < m;
i++) {
int u, v;
scanf("%d %d", &u, &v);
book[u] = book[v] = 1;
edge[u].push_back(v);
edge[v].push_back(u);
}
solve();
}
}
【FZU|FZU - 2112 Tickets (欧拉回路+联通块判断)】转载于:https://www.cnblogs.com/ACMFish/p/7222844.html
推荐阅读
- FZU - 2107题解
- FZU-2109 Mountain Number(数位dp)
- FZU - 2082 过路费(树链剖分)
- 线段树|FZU - 2277(树链剖分或dfs序+线段树)
- 2018211210康雪苗
- DP|fzu oj 2236 第十四个目标 树状数组好题 dp
- 201521123025第9周学习总结
- FZU 2236 第十四个目标 (线段树)
- ApacheCN Linux 译文集(二) 20211206 更新
- ApacheCN NodeJS 译文集 20211204 更新