食物鏈題解

sad_lin發表於2024-09-15

雙倍經驗:P2024 [NOI2001] 食物鏈

當問題要求維護一些對立的關係時(朋友、敵人),就可以用種類並查集實現。

因為有三種關係所以並查集的陣列要開三倍空間,第一倍空間存同類關係,第二倍存捕食關係,第三倍存被捕食關係。

注意:一的獵物的獵物就是一的天敵,其他就可以直接並查集維護即可。

注意這題是多組資料要多測清空

具體判斷可以程式碼,有詳細註釋,利於理解:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=50005*3;//三倍點 
int n,m;
int fa[N];
//查詢 
int find(int x){
	return fa[x]==x?x:find(fa[x]);
}
//合併 
void add(int u,int v){
	int x=find(u);
	int y=find(v);
	fa[x]=y;
}
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
    	cin>>n>>m;
		//初始化 
		for(int i=1;i<=3*n;i++){//
			fa[i]=i;
		}
		int ans=0;//注意多測 
		while(m--){
			int x,y,s;
			cin>>s>>x>>y;
			//編號超過n,假話。
			if(x>n||y>n){ 
				ans++;
				continue;
			}
			if(s==1){
				//成為同類但存在捕食關係,假話。 
				if(find(x+n)==find(y)||find(y+n)==find(x)){
					ans++;
				}
				else{
					add(x,y);//同類 
					add(x+n,y+n);//天敵之間也是同類 
					add(x+n+n,y+n+n);//天敵的天敵也是同類 
				}
			}
			else{
				//捕食存在同類和被捕食關係,假話
				if(find(x)==find(y)||find(y+n)==find(x)){
					ans++;
				}
				else{
					add(x+n,y);//x捕食y
					add(x+n+n,y+n);//天敵的捕食 
					add(x,y+n+n);//天敵的天敵也存在捕食關係 
				}
			}
		}
	   	cout<<ans<<"\n";
	}
    return 0;
}

相關文章