上一篇我簡單地封裝了一個並查集:【數據結構】之並查集簡易封裝
這次用它來解決一個食物鏈的問題:
/**
* 食物鏈問題:
* 有N只動物,編號爲1到N,所有動物都屬於A,B,C中的其中一種。
* 已知A喫B,B喫C,C喫A。
* 按順序給出以下兩種信息共K條:
* 第一種:x和y屬於同一種類。
* 第二種:x喫y。
* 然而這些信息可能會出錯:有可能有的信息和之前給出的信息矛盾,
* 也有可能此信息給出的x或者y不在1到N的範圍裏,請求出錯的信息條數
*/
#include <stdio.h>
#include "union_find.h"
/**
* 爲了測試方便,就不弄輸入了,直接用以下5行代碼來代表我們所輸入的信息
* 我們用T,X,Y三個數組來描述這K條信息
* 拿第一、二條(下標爲0和1)爲例,可以表示爲:
* 第1種:編號101和編號1屬於同一種類。
* 第2種:編號1喫編號2。
*/
#define N 100 //有100只動物
#define K 7 //有7條信息
static int T[K] = { 1,2,2,2,1,2,1}; //信息種類,1爲第一種,2爲第二種
static int X[K] = {101,1,2,3,1,3,5}; //信息中的x
static int Y[K] = { 1,2,3,3,3,1,5}; //信息中的y
/**
* 解題的大體思路
* 可以用並查集解決這個問題:
* 在給出信息之前,我們並不知道這100只動物是屬於哪一種類,
* 因此不妨枚舉出各個動物是3種物種的可能性,建立一個並查集數組data[N*3]
* 如:data[5],data[5+N],data[5+2*N]分別表示編號5動物分別屬於A,B,C種類
*/
int main() {
//用於統計錯誤信息數量
int error_msg_count = 0;
//創建一個N*3大小的並查集
UnionFind* uf = new_UnionFind(N * 3);
for (int i = 0; i < K; ++i) {
//題目中的編號是從1開始的,可以轉爲從0開始,方便計算
int x = X[i] - 1;
int y = Y[i] - 1;
int type = T[i];
//超出範圍直接判定爲錯誤信息
if (x < 0 || y < 0 || x >= N || y >= N){
error_msg_count++;
continue;
}
//第一種:x和y屬於同一種類
if (type == 1){
//當前信息與之前給出的信息相違背的情況
if (uf->same(uf, x, y+N) || uf->same(uf, x, y+2*N)){
error_msg_count++;
continue;
}
//沒有矛盾,就合併
uf->unite(uf, x, y);
uf->unite(uf, x+N, y+N);
uf->unite(uf, x+2*N, y+2*N);
}
//第二種:x喫y
else if (type == 2){
//當前信息與之前給出的信息相違背的情況
if (uf->same(uf, x, y) || uf->same(uf, x, y+2*N)){
error_msg_count++;
continue;
}
//沒有矛盾,就合併
uf->unite(uf, x, y+N);
uf->unite(uf, x+N, y+2*N);
uf->unite(uf, x+2*N, y);
}
}
printf("error_msg_count:%d", error_msg_count);
uf->delete(uf);
return 0;
}
運行結果:
error_msg_count:3
其中下標爲0,3,4的信息被判定爲錯誤信息