[FOJ 2112][Vjudge 35186] Tickets [并查集+一笔画问题]

来源:互联网 发布:log4cpp linux编译 编辑:程序博客网 时间:2024/04/30 10:21

给一个图,问最少加多少条边能让其一笔画出来

如果一个图是连通的且其中度为奇数的点的个数为0个或2个,那么可以一笔画出来

用并查集维护每个联通块的度为奇数的点的个数,如果大于2且为n个,那么需要补n/2条边(每条边让两个度为奇数的点变为偶数),最后再用联通块个数-1条边来将不同的联通块连起来

#include <cstdio>struct DisjoinSet {int f[100010];int num[100010];int deg[100010];int odd[100010];int n;void clear(int n) {for (int i=1;i<=n;i++) {deg[i]=0;odd[i]=0;f[i]=i;num[i]=1;}this->n=0;}void print(int n) {printf("deg[i]:");for (int i=1;i<=n;i++) printf("%d ",deg[i]);printf("\n");printf("num[i]:");for (int i=1;i<=n;i++) printf("%d ",num[i]);printf("\n");printf("odd[i]:");for (int i=1;i<=n;i++) printf("%d ",odd[i]);printf("\n");printf("fth[i]:");for (int i=1;i<=n;i++) printf("%d ",f[i]);printf("\n");}int get(int x) {if (f[x]==x) return x;return f[x]=get(f[x]);}void tosame(int x,int y) {deg[x]++;deg[y]++;x=get(x);y=get(y);if (x==y) return;if (num[y]==1&&num[x]==1) n++;else if (num[y]!=1&&num[x]!=1) n--;num[y]+=num[x];f[x]=y;}int getAns(int n) {int i;int ans=this->n-1;//printf("--%d\n",this->n);for (i=1;i<=n;i++) {if (deg[i]%2==1) odd[get(i)]++;}for (i=1;i<=n;i++) {if (odd[i]) ans+=odd[i]/2-1;}return ans;}};int n,m;DisjoinSet c;int main() {int t,x,y;scanf("%d",&t);while (t--) {scanf("%d%d",&n,&m);c.clear(n);//c.print(n);while (m--) {scanf("%d%d",&x,&y);c.tosame(x,y);//c.print(n);}printf("%d\n",c.getAns(n));//c.print(n);}return 0;}


0 0
原创粉丝点击