L2-010 排座位 (25分) 並查集

佈置宴席最微妙的事情,就是給前來參宴的各位賓客安排座位。無論如何,總不能把兩個死對頭排到同一張宴會桌旁!這個艱鉅任務現在就交給你,對任何一對客人,請編寫程序告訴主人他們是否能被安排同席。

輸入格式:
輸入第一行給出3個正整數:N(≤100),即前來參宴的賓客總人數,則這些人從1到N編號;M爲已知兩兩賓客之間的關係數;K爲查詢的條數。隨後M行,每行給出一對賓客之間的關係,格式爲:賓客1 賓客2 關係,其中關係爲1表示是朋友,-1表示是死對頭。注意兩個人不可能既是朋友又是敵人。最後K行,每行給出一對需要查詢的賓客編號。

這裏假設朋友的朋友也是朋友。但敵人的敵人並不一定就是朋友,朋友的敵人也不一定是敵人。只有單純直接的敵對關係纔是絕對不能同席的。

輸出格式:
對每個查詢輸出一行結果:如果兩位賓客之間是朋友,且沒有敵對關係,則輸出No problem;如果他們之間並不是朋友,但也不敵對,則輸出OK;如果他們之間有敵對,然而也有共同的朋友,則輸出OK but…;如果他們之間只有敵對關係,則輸出No way。

輸入樣例:

7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2

輸出樣例:

No problem
OK
OK but…
No way

朋友的朋友也是朋友(比如1和2是朋友,2和3是朋友,那麼1和3也是朋友),所以朋友關係可以用並查集做。

敵人的敵人不一定是敵人(比如1和2是敵人,2和3是敵人,但1和3不一定是敵人),所以敵人關係用一個二維數組標記即可。

#include<bits/stdc++.h>
using namespace std;
int m[105][105];
int p[105]; //p[x]: x結點的父結點,根結點的父結點是本身 

int find(int x) //返回x的祖宗結點+路徑優化 
{
	if(p[x] != x) p[x]=find(p[x]);
	return p[x];
}
int main()
{
	int N,M,K,x,y,z;
	cin>>N>>M>>K;
	
	for(int i=1; i<=N; i++) p[i]=i; 
	//剛開始所有元素在一個集合內,此時 p[x]=x 
	
	while(M--)
	{
		cin>>x>>y>>z;
		if(z==-1) //敵人 
		{
			m[x][y]=-1;
			m[y][x]=-1;
		}
		else
		{
		   if(find(x) != find(y))  // x,y不在同一集合 
		    p[find(x)] = find(y);  // 合併 
		}
	}
	while(K--)
	{
		cin>>x>>y;
		if(find(x) == find(y) && m[x][y] != -1)
		  cout<<"No problem"<<endl;
		if(find(x) != find(y) && m[x][y] != -1) 
		  cout<<"OK"<<endl;
		if(find(x) == find(y) && m[x][y] == -1)
		  cout<<"OK but..."<<endl;
		if(find(x) != find(y) && m[x][y] == -1)
		  cout<<"No way"<<endl;     
	}
}

有關並查集的講解:並查集算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章