种类并查集
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了种类并查集相关的知识,希望对你有一定的参考价值。
北京大学OJ1182
食物链
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 64641 | Accepted: 18999 |
Description
动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类。
第二种说法是"2 X Y",表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类。
第二种说法是"2 X Y",表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。
Input
第一行是两个整数N和K,以一个空格分隔。
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
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 code:
#include <iostream> #include <vector> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; std::vector<pair<int,int> > w; std::vector<pair<int,int> > d; int num,len,fakeNum; struct node{ int relation;//和父亲的关系,涉及到两个和两个以上的种类 int father;//父亲序号 //int value;//用于需要统计的题 }; std::vector<node> nodes; void init(){ for (int i = 0 ; i < num ; i++){ node nn; nn.father = i; //nn.value = 1; nn.relation = 0;//0代表是同一类,1代表吃掉父亲,2代表被父亲吃掉 nodes.push_back(nn); } } //不同题目这个函数会不同 int getRelation(int a, int b ){//已知a = (x,y) b = (y,z),求c = (x,z) int c = 0; if(a == 0){ return b; } if (a == 1){ if(b == 0){ return 1; } if(b == 1){ return 2; } if(b == 2){ return 0; } } if (a == 2){ if(b == 0){ return 2; } if(b == 1){ return 0; } if(b == 2){ return 1; } } } //不同题目这个函数会不同 int reverseRalation(int a){ if(a == 0){ return 0; } if(a == 1){ return 2; } if(a == 2){ return 1; } } void updateNode(int x, int root){//这里假设x的父亲是根节点或者是根节点的孩子 if (nodes[x].father == root){ return; } int f = nodes[x].father; //relation和value更新,不同题目规则不同 nodes[x].relation = getRelation(nodes[x].relation,nodes[f].relation); //nodes[f].value -= 1; nodes[x].father = root; } int getRoot(int x){ int fi = nodes[x].father; if (fi == x){ return fi; } int re = getRoot(fi); updateNode(x,re); return re; } void mergeUpdate(int x,int y,int xr,int yr,int relation){ nodes[yr].father = xr; //relation和value更新,不同题目规则不同 int xTOyr = getRelation(relation,nodes[y].relation); int yrTOx = reverseRalation(xTOyr); int yrTOxr= getRelation(yrTOx,nodes[x].relation); nodes[yr].relation = yrTOxr; //nodes[xr].value += nodes[yr].value; } bool isHarmonious(int x, int y, int relation){ int rTOy = reverseRalation(nodes[y].relation); int xTOy = getRelation(nodes[x].relation,rTOy); return relation == xTOy; } bool merge(int x , int y, int relation){ int xr = getRoot(x); int yr = getRoot(y); if(xr == yr){ return isHarmonious(x,y,relation); } else{ mergeUpdate(x,y,xr,yr,relation); return true; } } bool judge(int x , int y){ int xr = getRoot(x); int yr = getRoot(y); if (xr == yr){ return true; } else{ return false; } } int goodState(int type, int x, int y){ if (x>num || y > num){ return -1; } if (x==y && type!=1){ return -1; } return type-1; } struct data { int ty; int f; int s; }; std::vector<data> all; void input(){ fakeNum = 0; cin >> num >> len; init(); for (int i = 0 ; i < len ; i ++){ int ty; int f, s; scanf("%d%d%d",&ty,&f,&s); //cout << ty << " " << f << " " << s <<endl; data d; d.ty = ty; d.f = f; d.s = s; all.push_back( d ); // all.push_back(s); // if (ty == 1){ // d.push_back(make_pair<int,int>(f,s) ); // } // else{ // w.push_back(make_pair<int,int>(f,s) ); // } } for (int i = 0 ; i < len ; i ++){ int ty = all[i].ty; int f = all[i].f; int s = all[i].s; //cout << ty << " " << f << " " << s <<endl; int relation = goodState(ty , f , s); if (relation == -1){ fakeNum++; } else{ if (!merge(f-1,s-1,relation)){ fakeNum++; } } } //sort(all.begin(), all.end()); //std::vector<int>::iterator nown = unique(all.begin(), all.end()); //all.erase(nown,all.end()); //re = 0; } void calc(){ } void output(){ cout << fakeNum; // cout <<num << " "<< len << endl; // for (int i = 0 ; i < d.size() ; i ++){ // cout << "1 "<<" " <<d[i].first << " " << d[i].second <<endl; // } // for (int i = 0 ; i < w.size() ; i ++){ // cout << "2 "<<" " <<w[i].first << " " << w[i].second <<endl; // } // for (int i = 0 ; i < all.size() ; i ++){ // cout << all[i]<< " "; // } } int main(){ input(); calc(); output(); return 0; }
测例生成器:
#include <iostream> #include <vector> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> #include <cstdlib> using namespace std; int N=50000,K = 100000; int main(){ srand(unsigned(time(0))); cout << N << " " << K << endl; for (int i = 0 ; i < K ; i++){ cout << rand()%2+1 << " " << rand()%int(N+double(N)*0.01)+1<< " " << rand()%int(N+double(N)*0.01)+1<<endl; } }
以上是关于种类并查集的主要内容,如果未能解决你的问题,请参考以下文章
带权并查集(含种类并查集)经典模板 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug's life(简单) ③hihoCoder 1515 : 分数调查(示例代码(代