程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 1417 True Liars(並查集+DP)

POJ 1417 True Liars(並查集+DP)

編輯:C++入門知識

題目:給出p1+p2個人,其中p1個是好人,p2個是壞人。然後有一些關系 ,a說b是好人(壞人).其中沒有矛盾的,判斷是否有唯一解判斷哪些人是好人,哪些人是壞人。

其中比較重要的是,好人總說真話,壞人總說假話。不需要判斷矛盾。  


其中好人說真話,壞人說假話這點很重要。

那麼如果一個人說另一個人是好人,那麼如果這個人是好人,說明 對方確實是好人,如果這個是壞人,說明這句話是假的,對方也是壞人。

如果一個人說另一個人是壞人,那麼如果這個人是好人,說明對方是壞人,如果這個是壞人,說明 對方是好人。

也就是如果條件是yes說明這兩個是相同集合的,否則是兩個不同的集合。

用r[i]表示i結點與根結點的關系,0為相同集合,1為不同集合。這是一個經典的並查集問題。

這樣處理之後,還需要判斷是否唯一

我們通過並查集,可以將所有人分為若干個集合,其中對於每一個集合,又分為兩個集合(好人和壞人,但是不知道哪些是好人,哪些是壞人,我們只有相對關系)

接下來就是從所有大集合中的兩個小集合取一個,組成好人集合,判斷是否唯一。

背包問題,dp[i][j]表示前i個大集合,好人為j個的方案有多少種,或者dp[i][j]表示當前好人i個,壞人j個的情況有多少種

如果dp[cnt][p1]!=1說明方案不唯一,或者無解。

如果為1題目還需要輸出方案,這點比較糾結。用後一種DP的時候WA了好多次,而這題又卡內存,不能開三維數組,其實可以兩次DP解決。

後來采用前者DP,不斷從dp[cnt][p1]往前遞推,遞推的結果也必須是某個前趨狀態的dp值為1.


[cpp]
#include<iostream>  
#include<cstdio>  
#include<map>  
#include<cstring>  
#include<cmath>  
#include<vector>  
#include<algorithm>  
#include<set>  
#include<string>  
#include<queue>  
#define inf 1<<30  
#define M 60005  
#define N 605  
#define maxn 300005  
#define eps 1e-10  
#define zero(a) fabs(a)<eps  
#define Min(a,b) ((a)<(b)?(a):(b))  
#define Max(a,b) ((a)>(b)?(a):(b))  
#define pb(a) push_back(a)  
#define mem(a,b) memset(a,b,sizeof(a))  
#define LL long long  
#define lson step<<1  
#define rson step<<1|1  
#define MOD 1000000009  
#define sqr(a) ((a)*(a))  
using namespace std; 
int pre[N],r[N]; 
int p1,p2,p; 
bool vis[N]; 
int dp[N][N/2]; 
int cnt;   //最後分為幾個集合  
int a[N][2];  //a[i][0],a[i][1]分別表示把第i個集合分成的兩個部分  
vector<int> b[N][2]; 
int find(int x) 

    if(x!=pre[x]) 
    { 
        int f=pre[x]; 
        pre[x]=find(pre[x]); 
        r[x]=r[x]^r[f]; 
    } 
    return pre[x]; 

void Init() 

    for(int i=1; i<=p1+p2; i++) pre[i]=i,r[i]=0; 
    mem(vis,false); 
    cnt=1; 
    mem(a,0); 
    for(int i=0; i<N; i++) 
    { 
        b[i][0].clear(); 
        b[i][1].clear(); 
    } 

int main() 

    while(scanf("%d%d%d",&p,&p1,&p2)!=EOF&&p+p1+p2) 
    { 
        Init(); 
        while(p--) 
        { 
            int u,v; 
            char str[10]; 
            scanf("%d%d%s",&u,&v,str); 
            int k=(str[0]=='n'); 
            int ra=find(u),rb=find(v); 
            if(ra!=rb) 
            { 
                pre[ra]=rb; 
                r[ra]=r[u]^r[v]^k; 
            } 
        } 
        for(int i=1; i<=p1+p2; i++) 
        { 
            if(!vis[i]) 
            { 
                int f=find(i); 
                for(int j=i; j<=p1+p2; j++) 
                { 
                    if(find(j)==f) 
                    { 
                        vis[j]=true; 
                        b[cnt][r[j]].pb(j); 
                        a[cnt][r[j]]++; 
                    } 
                } 
                cnt++; 
            } 
        } 
        mem(dp,0); 
        dp[0][0]=1; 
        for(int i=1; i<cnt; i++) 
        { 
            for(int j=p1; j>=0; j--) 
            { 
                if(j-a[i][0]>=0) 
                    dp[i][j]+=dp[i-1][j-a[i][0]]; 
                if(j-a[i][1]>=0) 
                    dp[i][j]+=dp[i-1][j-a[i][1]]; 
            } 
        } 
        if(dp[cnt-1][p1]!=1) 
        { 
            printf("no\n"); 
            continue; 
        } 
        else 
        { 
            vector<int>ans; 
            ans.clear(); 
            for(int i=cnt-1; i>=1; i--) 
            { 
                if(p1-a[i][0]>=0&&p2-a[i][1]>=0&&dp[i-1][p1-a[i][0]]==1) 
                { 
                    for(int j=0; j<b[i][0].size(); j++) 
                    { 
                        ans.pb(b[i][0][j]); 
                    } 
                    p1-=a[i][0]; 
                    p2-=a[i][1]; 
                } 
                else if(p1-a[i][1]>=0&&p2-a[i][0]>=0&&dp[i-1][p1-a[i][1]]==1) 
                { 
                    for(int j=0; j<b[i][1].size(); j++) 
                    { 
                        ans.pb(b[i][1][j]); 
                    } 
                    p1-=a[i][1]; 
                    p2-=a[i][0]; 
                } 
            } 
            sort(ans.begin(),ans.end()); 
            for(int i=0; i<ans.size(); i++) printf("%d\n",ans[i]); 
            printf("end\n"); 
        } 
    } 
    return 0; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved