hdu 1272 使用set和并查集
http://acm.hdu.edu.cn/showproblem.php?pid=1272
这道题就是求图是不是连通无环,我觉得其实就是看看图是不是一棵最小生成树。
所以要是图满足条件,就必然有n个节点,n-1条边。但是题目中若只有 0 0一组数据也是可以的!!!!!这里WA了好多回。
所以我首先采用stl里面的set来直接判断:
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<set> #include<cstring> using namespace std; const int maxn = 1005; int n, m; int main() { set<int> s; int x, y; int tot = 0; while (scanf("%d%d", &x, &y) == 2) { if (x == -1 && y == -1) break; if (x == 0 && y == 0) printf("Yes\n");//!!!特判一下!!! else { tot++, s.insert(x), s.insert(y);//把点加入set,tot计录边的数目 for (int i = 1;; i++) { scanf("%d%d", &x, &y); if (x == 0 && y == 0) { if (s.size() == tot + 1) printf("Yes\n"); else printf("No\n"); s.clear(); tot = 0; break; } s.insert(x), s.insert(y); tot++; } } } return 0; }
当然,原本的做法是用并查集,效率比set高很多:
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<set> #include<cstring> using namespace std; const int maxn=100005; int n,m; int f[maxn],flag[maxn]; int find(int x) { return f[x]==x?x:f[x]=find(f[x]); } int Union(int x,int y) { int rx=find(x); int ry=find(y); if (rx==ry){ return 0; }else{ f[rx]=ry; return 1; } } int main() { int x,y,t,Flag; while(scanf("%d%d",&x,&y)==2) { memset(flag,0,sizeof(flag)); for (int i=1;i<=maxn;i++) f[i]=i; if (x==-1&&y==-1) break; if (x==0&&y==0) printf("Yes\n"); else { Union(x,y); flag[x]=1,flag[y]=1;//记录点已在图中 t=1,Flag=1;//开始存在一棵树。没有环。 while(scanf("%d%d",&x,&y)==2) { if (x==0&&y==0) break; if (flag[x]==0){t++,flag[x]=1;}//x是新节点,树+1 if (flag[y]==0){t++,flag[y]=1;}//y是新节点,树+1 if (Union(x,y)==0) Flag=0;//存在回路 else t--;//x,y合并,树-1 } if (Flag&&t==1) printf("Yes\n"); else printf("No\n"); } } return 0; }