题意:每条边过且只过一次,问至少要画几笔才能全部边都经过。孤立的点忽视。
#include <iostream> using namespace std; const int M=100000+10; int gree[M]; int father[M]; int rank1[M]; int save[M]; bool used[M]; bool mark[M]; void Make_Set(int x) { father[x]=x; rank1[x]=0; } int Find(int x) { int k=0; while(x!=father[x]) { save[k++]=x; x=father[x]; } for(int j=0; j<k; j++) father[save[j]]=x; return x; } void Union(int a,int b) { int x=Find(a); int y=Find(b); if(x==y) return; if(rank1[x]<rank1[y]) father[x]=y; else { father[y]=x; if(rank1[x]==rank1[y]) rank1[x]++; } } int main() { int n, m; while(~scanf("%d%d", &n, &m)) { memset(gree,0,sizeof(gree)); memset(used,0,sizeof(used)); memset(mark,0,sizeof(mark)); while(m--) { int a,b; scanf("%d%d",&a,&b); if (!used[a]) { used[a]=1; Make_Set(a); } if (!used[b]) { used[b]=1; Make_Set(b); } gree[a]++; gree[b]++; Union(a,b); } int ans=0; for(int i=1; i<=n; i++) { if(used[i]&&gree[i]%2==1) { if(mark[Find(i)]==0) mark[Find(i)]=1;//标记该块已经有奇数点了 ans++;//计算总奇数点 } } ans/=2;//累加,看有多少块没奇数点。。。mark[老大]==0没有奇数点 for(int i = 1; i <= n; i++) if(used[i]&&father[i]==i&&mark[i]==0) ans++; printf("%d ",ans); } return 0; }