HDU-3018-Ant Trip-欧拉回路+并查集
Ant Trip
这道题一开始觉得是并查集,稳了;wa
才想起来有两个重要条件
1、完全独立的点不算;
2、把点连起来的边(路)不能重复走:就是要判断欧拉回路,即每个点的度数是不是偶数;
遍历每个点,把度数为奇数的点的父节点对应的计数器加1;
最后把非独立父节点的计数器加起来:1、计数器为零的加1就可以2、非零的要除以2才行。
至于原因:
分析:我们假设n个村庄之间有k个连通分量,对于每一个连通分量,如果存在欧拉路径,那么该分量只需要一组蚂蚁就行;如果不存在欧拉路径,我们知道,要想遍历该分量所有的顶点且每条边只走一次,如果所有的顶点都有偶数个度数,那么就存在欧拉回路了,也只需要一组蚂蚁,如果存在奇数度数的顶点,而且又要想一笔画走完所有边,我们就要从这个顶点开始出发,到另一个奇数度数的顶点为止,即两个奇数度数的顶点确定一条路径,但该路径并不一定覆盖该连通分量中所有的顶点,对于其他的顶点,我们仍然遵循上面的步骤,这样对于每一个不存在欧拉路径的连通分量,需要的步数就等于该连通分量中所有奇数度顶点的个数除以2.分别把这些不存在欧拉路径的连通分量的步数加起来,然后再加上存在欧拉路径的个数,就是最终的结果了。
#include <bits/stdc++.h> using namespace std; int n,m; int fa[100000+10]; int cot[100000+10]; int du [100000+10]; void init(){ for(int i=1;i<=n;i++) fa[i] = i; memset(cot,0,sizeof(cot)); memset(du,0,sizeof(du)); } int fin(int x) { if(fa[x]==x)return x; else return fa[x] = fin(fa[x]); } void uni(int x,int y) { int px = fin(x); int py = fin(y); if(px==py)return ; else fa[px] = py; } int main(){ while(~scanf("%d%d",&n,&m)) { init(); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); uni(u,v); du[u]++; du[v]++; } for(int i=1;i<=n;i++) { int papa = fin(i); cot[papa] += du[i]%2; } int cnt =0; for(int i=1;i<=n;i++) { if(fin(i)==i) { if(du[i]==0)continue; else { if(cot[i]==0)cnt++; else cnt+=cot[i]/2; } } } printf("%d\n",cnt); } return 0; }
skr