題意就是:現在這裡有兩群人,一群人只會說真話,另一群人只會說假話,但你不知道這些人中哪些是說真話的,所以你就去問,然後得出一些資訊,其中你只問了是不是說真話的人這乙個問題。現在讓你去判斷這兩群人中哪些人是說真話的,如果可以判斷請按照公升序把說真話的人的編號說出,如果不能,輸出no
分析:首先對於這道題,我們可以很明顯的看出這是乙個牽扯到分類的問題,所以要有使用並查集的意識,然後就是去思考如何判斷哪些人是說真話的,這裡我們用的是判斷這p個人的分法是否唯一,從而避免糾結於判斷個人的真假問題。下面就是如何根據題意分類,我們可以看出如果乙個人說另乙個人是說真話的,那麼這兩個人應該是同類的,(假設a說b是說真話的,a若為說謊話的,那這句話為假,則b也為說假話的,反之也是這樣)這樣我們就可以在a和b之間建立聯絡,這個聯絡的意義是判斷這個節點是否和父節點同類,從而得出多個集合,每個集合都會有一群跟父節點同類的和不同類的,然後把這幾個集合同類的相加,如得出再所有的集合相加的情況下人數為p的分法唯一,則代表可以分辨。這裡又產生乙個問題:這p個人一定全部是說真話的?因為在題目中已經告知說真話的人就是p人,那麼既然組成p人的方法唯一那麼,很顯然這個組法一定是說真話的人
**:
#include#include#include#includeusing namespace std;
const int maxn=610;
int dp[maxn][maxn],tag[maxn][2],ranks[maxn],pre[maxn],path[maxn][maxn],road[maxn][maxn],re[maxn];
int find(int x)
void join(int x,int y,int d)
return ;
}void ini()
memset(path,0,sizeof (path));//用來後面的路徑記錄
memset(dp,0,sizeof(dp));//dp[i][j]表示統計到第i個集合人數為j時的方法數
memset(tag,0,sizeof(tag));//計算每個集合中跟父節點同類和異類的個數。
memset(road,0,sizeof(road));//標記路徑
memset(re,0,sizeof(re));//統計集合並給每個集合標記乙個數
return ;
}void print(int tot,int p,int q)
else
j -= road[i][j];
}for(int i = 1;i <= p+q;i++)
}printf("end\n");
return ;
}void solve(int tot,int p,int q)
if( j - tag[i][1] >= 0 && dp[i-1][ j-tag[i][1] ] )}}
if(dp[tot][p]!=1) printf("no\n");
else
return ;
}int check(int p,int q)
}for(int i=1;i<=p+q;i++)
return tot;
}int main()
join(a,b,d);
}int tot=check(p,q);
solve(tot,p,q);
}// system("pause");
return 0;
}
poj1417 種類並查集 dp
題目 題意 輸入三個數m,p,q 分別表示接下來的輸入行數,天使數目,惡魔數目 接下來m行輸入形如x,y,ch,ch為yes表示x說y是天使,ch為no表示x說y不是天使 x,y為天使,惡魔的編號,1 x,y p q 天使只說真話,惡魔只說假話 如果不能確定所有天使的編號,輸出no,若能確定,輸出所...
poj1182 種類並查集
有點坑的題目,不過做做絕對利大於弊,尤其在你不斷wa到哭的時候,大神忽略這句 0 兩者相同級別 1 被根節點吃 2 吃根節點 原因 對於輸入的關係1和2,減1之後便是輸入的兩個量之間的關係 其實是寫完題目之後看解題報告發現這規律的 include include using namespace st...
POJ 1703 種類並查集
題意 乙個城市裡面有兩個黑幫 有兩種操作 a ask 詢問 x,y的關係 d x,y是一夥的 很明顯是種類並查集 於是就yy一下 relationsi 表示與父節點的關係 fatheri 記錄父節點 在合併和查詢root的時候 relations 更新注意一下就可以了 include include...