日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

POJ 1182 食物链 (并查集解法)(详细注释)

發布時間:2024/4/19 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 POJ 1182 食物链 (并查集解法)(详细注释) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

食物鏈
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 78510 Accepted: 23396
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

這題一看就是并查集,但是要注意的一點是第一句話:
    動物王國中有三類動物A,B,C,這三類動物的食物鏈構成了有趣的環形。A吃B, B吃C,C吃A。
意思就是所有的種類只有A,B,C三種,只有三個關系A吃B, B吃C,C吃A。

這點看清楚就好做了。

思路:我們創建3個分組i-A,i-B,i-C。

如果x和y是同類,正確則合并x-A和y-A、x-B和y-B、x-C和y-C。
        當存在x吃y或者y吃x時不正確。

如果x吃y,正確則合并x-A和y-B、x-B和y-C、x-C和y-A。
      當存在x和y是同類或者y吃x時不正確。

代碼:

#include <iostream> #include <stdio.h> using namespace std; typedef long long ll; #define MAX_N 50010 #define MAX_K 100010//輸入 int N,K; //類型+X+Y int T[MAX_K],X[MAX_K],Y[MAX_K]; int par[3*MAX_N]; //par[i]表示i節點的父節點 int rank[3*MAX_N]; // 樹的高度 //初始化n個元素 void init(int n){for(int i = 0;i < n; i++){par[i] = i;rank[i] = 0;} } //查詢包含x節點的樹的根 int find(int x){if(par[x] == x) return x;else return par[x] = find(par[x]); }//合并 x和y所屬的集合 void unite(int x,int y){x = find(x);y = find(y);if(x == y) return;if(rank[x] < rank[y]){par[x] = y; }else{par[y] = x;if(rank[x] == rank[y]) rank[x]++;} }//判斷x和y是否屬于同一個集合 bool same(int x,int y){return find(x) == find(y); }void solve(){//初始化3倍的點,0~(n-1)屬于A類,n~(2n-1)屬于B類,2n~(3n-1)屬于C類 init(N*3);int ans = 0;for(int i = 0;i < K; i++){int t = T[i];int x = X[i] - 1,y = Y[i] - 1;if(x < 0|| N <= x || y < 0 || N <= y){ans++;continue;}//分析x和y是同類是否正確 if(t == 1){//如果x吃y || y吃x就不正確 if(same(x,y+N) || same(x,y+2*N)){ans++;}else{//x和y是同類 正確 unite(x, y); //如果x屬于A,y就屬于A unite(x+N, y+N); //如果x屬于B,y就屬于B unite(x+N*2, y+N*2); //如果x屬于C,y就屬于C}}else{//分析x吃y是否正確 //如果x和y是同類 || y吃x就不正確 if(same(x,y) || same(x,y+2*N)){ans++;}else{unite(x,y+N); //如果x屬于A,那么y就屬于B unite(x+N,y+2*N); //如果x屬于B,那么y就屬于C unite(x+2*N,y); //如果x屬于C,那么y就屬于A}}} cout << ans << endl; }int main(){cin >> N >> K;for(int i = 0;i < K; i++){scanf("%d%d%d",&T[i],&X[i],&Y[i]);}solve();return 0; }

總結

以上是生活随笔為你收集整理的POJ 1182 食物链 (并查集解法)(详细注释)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。