Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 55882 | Accepted: 16377 |
Description
Input
Output
Sample Input
100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5
Sample Output
3
Source
以食物链为例,并查集是维护属于同一组的数据结构,但是本题不只有同一组,还有捕食关系。
对每只动物建立三个元素 i-A i-B i-C,用3 x n个元素建立并查集。
i - x 表示 i 属于种类x
并查集的每一个组,表示组里所有元素代表的情况,同时发生或者同时不发生
例如 如果 i-A j - B在一个集合里,说明 i 属于A的同时 j一定属于B,
所以对应题目中的两种情况,
1 x ,y属于同一种类,那么我们就合并 x-A y-A , x-B y-B , x-C y-C;
2 x吃 y ,那么我们就合并 x-A y-B , x-B y-C , x-C y-A;
当然合并的时候要进行判断是否有矛盾,具体来看代码吧
以上参照了挑战程序设计竞赛
【源码】
#include<iostream> #include<cstdio> using namespace std; const int maxn = 50000 + 10l; int father[maxn * 3]; int find(int x){ if(x == father[x]) return x; else return father[x] = find(father[x]); } void Union(int x,int y){ int xr = find(x); int yr = find(y); if(xr == yr) return ; father[xr] = yr; } bool same(int x,int y){ //判断是否为一组 return find(x) == find(y); } int main(){ int n,m; scanf("%d%d",&n,&m); //noi的题,没有eof int ans = 0; for(int i=0;i<=3*n;i++) father[i] = i; //注意这里是3*n for(int i=0;i<m;i++){ int t,x,y; scanf("%d%d%d",&t,&x,&y); if(x <=0 || x>n || y<=0 || y>n) { //数据错误 ans++ ans ++ ; continue; } if(t == 1){ if(same(x,y+n) || same(x,y+2*n)) //如果 x 与 y+n 或 y+2n同组就有矛盾 ans++; else{ Union(x,y); Union(x+n,y+n); Union(x+2*n,y+2*n); } } else{ if(same(x,y) || same(x,y+2*n)) //如果x 吃 x 或者 x 与 y 的“食物”在同一集合 ans++; else{ Union(x,y+n); Union(x+n,y+2*n); Union(x+2*n,y); } } // cout<<i<<" "<<ans<<"bbb"<<endl; } printf("%d\n",ans); return 0; }
HDU1829
给出 一对一对虫子的关系,可能是 公-母 也可能是 母-公
判断给出的关系对会不会出现同性的情况。
同样可以用上面的方法,对于每种关系 建立两个集合 Union(x,y+n) Union(y,x+n)
这两个集合有一个是真的。
然后在每次合并之前检查 x,y是否在同一集合即可,如果在同一集合就输出找到错误。
【源码】
#include<iostream> #include<cstdio> using namespace std; const int maxn = 2000 + 10l; int father[maxn * 3]; int find(int x){ if(x == father[x]) return x; else return father[x] = find(father[x]); } void Union(int x,int y){ int xr = find(x); int yr = find(y); if(xr == yr) return ; father[xr] = yr; } bool same(int x,int y){ return find(x) == find(y); } int main(){ int t; scanf("%d",&t); int cas = 1; while(t--){ printf("Scenario #%d:\n",cas++); int n,m,a,b; int flag = 0; scanf("%d%d",&n,&m); for(int i=0;i<=n*2;i++) father[i] = i; for(int i=0;i<m;i++){ scanf("%d%d",&a,&b); if(same(a,b) || same(b,a)) flag = 1; else{ if(!flag){ Union(a,b+n); Union(b,a+n); } } } if(flag) printf("Suspicious bugs found!\n"); else printf("No suspicious bugs found!\n"); puts(""); } return 0; }
printf("Scenario #%d:\n",cas++);
给出BFS染色的代码
【源码】
#include<iostream> #include<queue> #include<vector> #include<cstdio> #include<cstring> using namespace std; const int maxn =2100; vector<int>G[maxn]; int color[maxn]; int vis[maxn]; void init(){ for(int i=0;i<maxn ;i++){ G[i].clear(); color[i]=-1; } } bool bicolorable(int x){//染色法 queue<int>Q; Q.push(x); color[x] = 1; //没标记的染色为1 while(!Q.empty()){ int v1 = Q.front(); Q.pop(); for(int i=0;i<G[v1].size();i++){ int v2 = G[v1][i]; if(color[v2]==-1){ //相邻节点没染色 color[v2] = !color[v1]; Q.push(v2); } else if(color[v2]==color[v1]){ //相邻节点染色了,且与本身颜色一样 return false; } } } return true; } int main(){ int n,m; int t,kase = 0; cin>>t; while(t--){ init(); cin>>n>>m; int a,b; for(int i=0;i<m;i++){ cin>>a>>b; G[a].push_back(b); G[b].push_back(a); } int i; int fla = 0; for(i=1;i<=n;i++){ if(color[i] == -1){ //对每个没有染色的节点 染色 if(!bicolorable(i)){ fla = 1,i = n+1; } } } printf("Scenario #%d:\n", ++kase); //因为少了这句!! T^T if(!fla) cout<<"No suspicious bugs found!"<<endl; else cout<<"Suspicious bugs found!"<<endl; puts(""); } return 0; }