[POJ 1417 ---真嘘つき]種類互いに素なセットの+ DP +背中のバックパック

[POJ 1417 ---真嘘つき]種類互いに素なセットの+ DP +背中のバックパック

トピック出典:入力するようにクリックして、[POJ 2236 -ワイヤレスネットワーク]

説明

日のカップルのための小さなボートで約漂流した後、アキラクルーソー前田は最終的に霧の島に漂着しました。彼は疲れと絶望でしたが、彼はまだ彼が子供の頃に族長たちから聞いていた霧の島の伝説を覚えて幸運でした。これは、伝説の島でなければなりません。伝説では、二つの部族が島に住んでいる、人は神であり、他は、悪魔のようである神の部族のメンバーがあなたを祝福した後、メンバーと、対照的に、あなたの未来は明るいと有望である、そして、あなたの魂は最終的に天国に行きます悪魔のような部族の呪いあなたのことを、あなたの将来は暗いと絶望的で、あなたの魂は、最終的に地獄に落ちるだろう。

最悪のシナリオを回避するために、アキラは神から悪魔を区別する必要があります。しかし、どのように?彼らは全く同じに見えたし、彼はもっぱら自分の外見により互いに区別することができませんでした。彼はまだしかし、彼の最後の希望を持っていました。神の部族のメンバーは、真実テラーであり、彼らは常に真実を伝えると、悪魔のような部族のものは嘘つきです、彼らはいつも嘘をつく、あるあります。

彼はいくつかの神のかどうか、それらのいくつかを尋ねました。彼らは非常にお互いを知っていたし、常に「忠実」個々の性質(すなわち、彼らは常に真実か、常に嘘をつく)によると、彼に答えました。彼は伝説は、彼が質問好きではなかったときに悪魔のようなメンバーは永遠に人を呪うだろうと言っているので、質問のいずれかの他の形態を依頼する勇気がなかったです。彼は伝説は、両方の部族の集団を告げる便利informationfの別の部分を持っていました。この島に住むすべての人は不滅であるとどれもこれまでに、少なくともこれらの千年に生まれされていないので、凡例にこれらの数字は信頼できます。

あなたは良いコンピュータプログラマーですので、彼の問い合わせにその答えに応じて住民を分類プログラムを書き込むことによって、ヘルプアキラに要請しました。

入力

入力は複数のデータセットから構成され、次の形式でそれぞれ:

N P1 P2
XLイルA1
X2 Y2 A2
...
XI YIどちらか
...
XNがあります

最初の行は、3つの非負の整数nは、P1、P2とがあります。nはアキラが尋ねた質問の数です。PLとp2は伝説では、それぞれ、神と悪魔のような部族の集団です。次のn行のそれぞれ2つの整数XI、YI 1つのワード愛を有します。xiとyiが、1とP1 + P2との間の包括的であり、その各々は住民の識別番号です。住民xiは住民YIがそうでなければ、何の神の部族のメンバー、あるいはなかったと言った場合、AIは、どちらかyesです。xiとyiのは、以来、同じ数であることを、「あなたは神の部族のメンバーですか?」メモは有効な質問です。2行は同じxのを有していてもよく、yはアキラは非常に動揺していますので複数回同じものに同じ質問をしたかもしれないことにも注意してください。

あなたは、nが1000未満であり、そのP1およびP2、すなわち三つのゼロ未満300 A線、0 0であり、入力の終了を表すと仮定してもよいです。あなたは、各データセットが一貫していると何の矛盾した答えが含まれていないと仮定することができます。

出力

それはすべての住民を分類するために十分な情報を含む場合、各データ・セットについては、昇順に全て神のもの、ライン内の1つの識別番号を印刷します。また、出力数以下、行の終わりをプリントします。与えられたデータセットは、すべて神のメンバーを識別するのに十分な情報が含まれていない場合はそうでない場合、すなわち、ラインに何を印刷しません。

サンプル入力

2 1 1
1 2無
2 1ない
3 2 1
1 1はい
2 2はい
3 3はい
2 2 1
1 2はい
2 3無
5 4 3
1 2はい
1 3無
4はい
5 6はい
6 7ない
0 0

サンプル出力

なし
なし
1つの
2

3
4
5
6

問題解決のためのアイデア

既知の問題の意味解析することにより:、xのX、Y、はい代わっ、yの特定の種類を入力し、X、Y、Xとなしのテーブルを入力し、yは確かに同じではありません。
我々は簡単に= 1、xは父親に属するノードを表す[X]ランク、= 0 xは同じノードに属して父親を表し、[x]は、[x]は互いに素セット、RKの種類は、xとその親ノードとの間の関係を表してRKを想像することができますので、異種;互いに素なセットによる結合の各数は、2つの部分に分けることができ、そして金属の同じ種類のルートノード、ならびにルートノードとノードが不均一に属している数値のセットとの間の相対的な関係を決定することができるであろう。

我々は、ノードの数と異なるノードの数、ルートノードと内部の各セットと同じ種類のコレクションの分割数を決定し、その後のセットに対応する部分からノード(またはすべてのセット)を選択した、選択されたすべてのノードであれば選挙は、我々は問題は完璧な解決策になることができナップザックに使用できる何かがある方法についてのDP方法; p1はユニークな選択方法の数の合計が、我々はその逆はないすべての天使の数を決定することができますです。

Jのi番目の値のノードの数がARRによって設定されたマーク[I] [J]します。
DPは== [i]はi番目のセットの種類を選択する[j]はj及び方法の合計数であり、すなわち、DP [NUM] [P1]で表される 1 ;答えが決定されイネーブルされ
、その後、バックノードかを決定します。

ACコード:

#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
const int MAXN = 605;
int pre[MAXN],rk[MAXN],cnt[MAXN],arr[MAXN][2],dp[MAXN][MAXN],lj[MAXN][MAXN];
bool ans[MAXN][2];

void init(int n)
{
    memset(rk,0,sizeof(rk));
    memset(cnt,0,sizeof(cnt));
    memset(arr,0,sizeof(arr));
    memset(dp,0,sizeof(dp));
    memset(lj,0,sizeof(lj));
    memset(ans,false,sizeof(ans));
    for(int i=0;i<=n;i++)
        pre[i]=i;
}

int _find(int x)
{
    if(x==pre[x]) return x;
    int p=pre[x];
    pre[x]=_find(pre[x]);
    rk[x]=rk[x]^rk[p];
    return pre[x];
}

void unite(int a,int b,int c)
{
    int x=_find(a);
    int y=_find(b);
    if(x==y) return;
    pre[x]=y;
    rk[x]=rk[a]^rk[b]^c;
}

int main()
{
    SIS;
    int n,p1,p2,x,y,pos;
    string s;
    while(cin >> n >> p1 >> p2, n+p1+p2)
    {
        pos=p1+p2;
        init(pos);
        for(int i=0;i<n;i++)
        {
            cin >> x >> y >> s;
            if(s[0]=='y') unite(x,y,0);
            else unite(x,y,1);
        }
        int num=0;
        for(int i=1;i<=pos;i++)
            if(pre[i]==i) cnt[i]=++num;
        for(int i=1;i<=pos;i++)
            arr[cnt[_find(i)]][rk[i]]++;
        dp[0][0]=1;
        for(int i=1;i<=num;i++)
        {
            x=min(arr[i][0],arr[i][1]);
            for(int j=p1;j>=x;j--)
            {
                if(dp[i-1][j-arr[i][0]])
                    dp[i][j]+=dp[i-1][j-arr[i][0]],lj[i][j]=arr[i][0];
                if(dp[i-1][j-arr[i][1]])
                    dp[i][j]+=dp[i-1][j-arr[i][1]],lj[i][j]=arr[i][1];
            }
        }
        if(dp[num][p1]!=1) { cout << "no" << endl; continue;}
        for(int i=num,j=p1;i>0;i--)
        {
            if(lj[i][j]==arr[i][0]) ans[i][0]=true;
            else ans[i][1]=true;
            j-=lj[i][j];
        }
        for(int i=1;i<=pos;i++)
            if(ans[cnt[_find(i)]][rk[i]]) 
                cout << i << endl;
        cout << "end" << endl;
    }
    return 0;
}
公開された412元の記事 ウォンの賞賛135 ・は 40000 +を見て

おすすめ

転載: blog.csdn.net/qq_41879343/article/details/104164119