POJ 1182 食物链 [并查集 带权并查集 开拓思路]

传送门

P - 食物链

Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u

Submit Status Practice POJ 1182

Appoint description: 
System Crawler  (2015-01-27)

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),输出假话的总数。

Input

第一行是两个整数N和K,以一个空格分隔。 
以下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

先吐槽一下关于多组样例的问题,闲话也不多说,这题网上大牛各种神奇的题解都有,第一份代码是常规带权并查集的做法,不多谈,我主要想谈一下第二份代码的思路。

如果我们换一个思路,把1--n看成与自身同类的集合,1+n--2*n看成自己吃的集合,1+2*n--3*n看成吃自己的集合,那么问题便简单多了~~~

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<string>
 12
 13 #define N 50005
 14 #define M 105
 15 #define mod 1000000007
 16 //#define p 10000007
 17 #define mod2 1000000000
 18 #define ll long long
 19 #define LL long long
 20 #define eps 1e-6
 21 #define inf 100000000
 22 #define maxi(a,b) (a)>(b)? (a) : (b)
 23 #define mini(a,b) (a)<(b)? (a) : (b)
 24
 25 using namespace std;
 26
 27 int n,m;
 28 int f[N];
 29 int r[N];
 30 int ans;
 31
 32 void ini()
 33 {
 34     ans=0;
 35     int i;
 36     for(i=0;i<=n;i++){
 37         f[i]=i;
 38         r[i]=0;
 39     }
 40 }
 41
 42 int find(int x)
 43 {
 44     int fa;
 45     if(f[x]!=x)
 46     {
 47         fa=find(f[x]);
 48         r[x]=(r[x]+r[ f[x] ])%3;
 49         f[x]=fa;
 50     }
 51     return f[x];
 52 }
 53
 54 void merge(int x,int y,int d)
 55 {
 56     int a,b;
 57     a=find(x);
 58     b=find(y);
 59     if(a==b){
 60         return;
 61     }
 62     f[b]=a;
 63     r[b]=(3-r[y]+r[x]+d)%3;
 64 }
 65
 66 void solve()
 67 {
 68     int d,x,y;
 69     int a,b;
 70     int re;
 71     int i;
 72     for(i=1;i<=m;i++){
 73         scanf("%d%d%d",&d,&x,&y);
 74         if(x>n || y>n){
 75             ans++;continue;
 76         }
 77         if(d==2 && x==y){
 78             ans++;continue;
 79         }
 80         a=find(x);
 81         b=find(y);
 82         re=(3-r[x]+r[y])%3;
 83         if(a==b && re!=d-1){
 84             ans++;continue;
 85         }
 86         //printf(" i=%d\n",i);
 87         merge(x,y,d-1);
 88     }
 89 }
 90
 91 void out()
 92 {
 93     printf("%d\n",ans);
 94 }
 95
 96 int main()
 97 {
 98     //freopen("data.in","r",stdin);
 99     //freopen("data.out","w",stdout);
100     //scanf("%d",&T);
101     //for(int ccnt=1;ccnt<=T;ccnt++)
102     //while(T--)
103     //while(scanf("%d%d",&n,&m)!=EOF)
104     scanf("%d%d",&n,&m);
105     {
106         ini();
107         solve();
108         out();
109     }
110     return 0;
111 }

如果我们换一个思路,把1--n看成与自身同类的集合,1+n--2*n看成自己吃的集合,1+2*n--3*n看成吃自己的集合,那么问题便简单多了~~~

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<string>
 12
 13 #define N 50005
 14 #define M 105
 15 #define mod 1000000007
 16 //#define p 10000007
 17 #define mod2 1000000000
 18 #define ll long long
 19 #define LL long long
 20 #define eps 1e-6
 21 #define inf 100000000
 22 #define maxi(a,b) (a)>(b)? (a) : (b)
 23 #define mini(a,b) (a)<(b)? (a) : (b)
 24
 25 using namespace std;
 26
 27 int n,m;
 28 int f[3*N];
 29 int ans;
 30
 31 void ini()
 32 {
 33     ans=0;
 34     int i;
 35     for(i=0;i<=3*n;i++){
 36         f[i]=i;
 37     }
 38 }
 39
 40 int find(int x)
 41 {
 42     int fa;
 43     if(f[x]!=x)
 44     {
 45         fa=find(f[x]);
 46         f[x]=fa;
 47     }
 48     return f[x];
 49 }
 50
 51 void merge(int x,int y)
 52 {
 53     int a,b;
 54     a=find(x);
 55     b=find(y);
 56     if(a==b){
 57         return;
 58     }
 59     f[b]=a;
 60 }
 61
 62 void solve()
 63 {
 64     int d,x,y;
 65     int a,b;
 66     int fx,sx;
 67     int i;
 68     for(i=1;i<=m;i++){
 69         scanf("%d%d%d",&d,&x,&y);
 70         if(x>n || y>n){
 71             ans++;continue;
 72         }
 73         if(d==2 && x==y){
 74             ans++;continue;
 75         }
 76         a=find(x);
 77         b=find(y);
 78         fx=find(x+n);
 79         sx=find(x+2*n);
 80         if(d==1){
 81             if(b==fx || b==sx){
 82                 ans++;continue;
 83             }
 84             else{
 85                 merge(x,y);
 86                 merge(x+n,y+n);
 87                 merge(x+2*n,y+2*n);
 88             }
 89         }
 90         else{
 91             if(b==a || b==sx){
 92                 ans++;continue;
 93             }
 94             else{
 95                 merge(x+n,y);
 96                 merge(x+2*n,y+n);
 97                 merge(x,y+2*n);
 98             }
 99         }
100     }
101 }
102
103 void out()
104 {
105     printf("%d\n",ans);
106 }
107
108 int main()
109 {
110     //freopen("data.in","r",stdin);
111     //freopen("data.out","w",stdout);
112     //scanf("%d",&T);
113     //for(int ccnt=1;ccnt<=T;ccnt++)
114     //while(T--)
115     //while(scanf("%d%d",&n,&m)!=EOF)
116     scanf("%d%d",&n,&m);
117     {
118         ini();
119         solve();
120         out();
121     }
122     return 0;
123 }
时间: 2024-10-13 23:29:41

POJ 1182 食物链 [并查集 带权并查集 开拓思路]的相关文章

poj 1182 食物链 &amp;&amp; nyoj 207(带权并查集)

食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 52414   Accepted: 15346 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同

POJ 2492 A Bug&#39;s Life (带权并查集 &amp;&amp; 向量偏移)

题意 : 给你 n 只虫且性别只有公母, 接下来给出 m 个关系, 这 m 个关系中都是代表这两只虫能够交配, 就是默认异性, 问你在给出的关系中有没有与异性交配这一事实相反的, 即同性之间给出了交配关系. 分析 : 本题雷同POJ 1182 食物链, 如果会了那一题, 那现在这题便简单多了, 建议先了解食物链的偏移向量做法.这里也是使用向量的思考方式来进行relation的变化, 这里我令 relation = 0为同性, relation = 1为异性, 接下来的步骤就和食物链的雷同了. 优

POJ 1984 Navigation Nightmare 二维带权并查集

题目来源:POJ 1984 Navigation Nightmare 题意:给你一颗树 k次询问 求2点之间的曼哈顿距离 并且要在只有开始k条边的情况下 思路:按照方向 我是以左上角为根 左上角为原点 dx[i]为i点距离根的x坐标 dy[]是y坐标 这两个可以通过路径压缩求出 只不过是二维而已 #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; const int m

【POJ 1984】Navigation Nightmare(带权并查集)

Navigation Nightmare Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usually numbered/labeled 1..N. A series of M (1 <= M < 40,000) vertical and horizontal roads each of varying lengths (1 <= length <= 100

POJ 1984 Navigation Nightmare 【经典带权并查集】

任意门:http://poj.org/problem?id=1984 Navigation Nightmare Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 7783   Accepted: 2801 Case Time Limit: 1000MS Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usuall

POJ1182 食物链(必做经典带权并查集)

  分析:   本题最重要的是通过向量的想法来解决这一类关系,这样思维难度大大降低,首先我们明白一点   根据传递性的定义(也就是离散数学中的传递性),x->y =x->z+z>y   我们要知道的一点是,并查集中的题目都是有传递性的,而传递性的题目并不一定能通过并查集解决   我们知道我们要将两个不同的集合合并,就是将他们的头结点合并,所以我们需要知道d[pa]的大小是多少   那么我们定义pa->pb的关系就等于 pa->x+x->y+y->pb,其中x-&g

POJ - 3728:The merchant (Tarjan 带权并查集)

题意:给定一个N个节点的树,1<=N<=50000 每个节点都有一个权值,代表商品在这个节点的价格.商人从某个节点a移动到节点b,且只能购买并出售一次商品,问最多可以产生多大的利润. 思路:路径压缩,得到每个点到当前根的信息,然后更新即可. 有可以用倍增做. 很久前抄的代码. #include<cstdio> #define min(a,b) (a<b?a:b) #define max(a,b) (a>b?a:b) #define swap(a,b) (a^=b,b^=

poj 1733Parity game(map离散+带权并查集)

Parity game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7567   Accepted: 2951 Description Now and then you play the following game with your friend. Your friend writes down a sequence consisting of zeroes and ones. You choose a conti

【并查集&amp;&amp;带权并查集】BZOJ3296&amp;&amp;POJ1182

bzoj1529[POI2005]ska Piggy banks [题目大意] n头奶牛m种语言,每种奶牛分别掌握一些语言.问至少再让奶牛多学多少种语言,才能使得它们能够直接或间接交流? [思路] (n+m)个点,奶牛学会某种语言就合并它和语言的节点.并查集维护联通块,答案为联通块个数-1.水,可是我跳坑了. 我一开始做法是设总的联通块有(n+m)个,然后没合并一次减去1.其实这样是不可行的,因为我们只需要考虑奶牛(即节点1..n)有几个联通块.有可能一些语言根本没有任何奶牛掌握-- 1 #in