zoukankan      html  css  js  c++  java
  • POJ 1417 True Liars (并查集+dp+路径输出)

    题解思路:

    通过题意可以推出如果回答为yes,则a b同族,no为不同族;

    并查集维护,可以知道有几棵树;

    用cnt[i][1 / 0]表示每棵树里2类人各有多少;

    看能否拼出为一个解;

    dp[i][j]表示前i棵树,可以拼成j个人的个数,

    转移方程 dp[i][j]=dp[i-1][j-cnt[i][0]],dp[i-1][j-cnt[i][1]])注意这里是俩类人力必选一类;

    dp倒退回去,记录路径输出;

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<map>
    #include<queue>
    #include<stack>
    #include<set>
    
    #define ll long long
    #define mem(a,b) memset(a,b,sizeof(a))
    
    const int maxn=600+50;
    
    using namespace std;
    
    int f[maxn],sum[maxn],d[maxn][301],cnt[maxn][2],vis[maxn],choose[maxn];
    //   父      路径       dp          记录每类人的数量 重新标号   选择了0/1
    
    int root(int x)
    {
        if(f[x]==x) return x;
        int rt=root(f[x]);
        sum[x]^=sum[f[x]];
        return f[x]=rt;
    }
    
    void init()
    {
        mem(sum,0);
        mem(d,0);
        mem(cnt,0);
        mem(vis,0);
        mem(choose,0);
    }
    
    int main(){
        int n,s1,s2,a,b,x,y,v,tot;char s[5];
        while(~scanf("%d%d%d",&n,&s1,&s2))
        {
            if(n+s1+s2==0) break;
            tot=0;
            init();
            for(int i=1;i<=s1+s2;i++) f[i]=i;
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d%s",&a,&b,s);
                s[0]=='y'?v=0:v=1;
                x=root(a);
                y=root(b);
                if(x!=y)
                {
                    f[x]=y;
                    sum[x]=sum[a]^sum[b]^v;
                }
            }
            for(int i=1;i<=s1+s2;i++)//重新标号
            {
                if(!vis[root(i)]) vis[f[i]]=++tot;
                if(sum[i]==0)
                    cnt[vis[f[i]]][0]++;
                else
                    cnt[vis[f[i]]][1]++;
            }
    //        for(int i=1;i<=tot;i++)
    //        {
    //            cout<<cnt[i][0]<<" "<<cnt[i][1]<<endl;
    //        }cout<<endl;
            d[0][0]=1;
            for(int i=1;i<=tot;i++)//dp
            {
                for(int j=0;j<=s1;j++)
                {
                    if(j>=cnt[i][1])
                        d[i][j]+=d[i-1][j-cnt[i][1]];
                    if(j>=cnt[i][0])
                        d[i][j]+=d[i-1][j-cnt[i][0]];
                }
            }
    //        for(int i=1;i<=tot;i++)
    //        {
    //            for(int j=1;j<=s1;j++)
    //                cout<<d[i][j]<<" ";
    //            cout<<endl;
    //        }
            if(d[tot][s1]==1)
            {
                int l=s1;
                for(int i=tot;i>0;i--)//倒推路径
                {
                    if(d[i][l]==d[i-1][l-cnt[i][1]])
                    {
                        choose[i]=1;
                        l-=cnt[i][1];
                    }
                    else if(d[i][l]==d[i-1][l-cnt[i][0]])
                    {
                        choose[i]=0;
                        l-=cnt[i][0];
                    }
                }
                for(int i=1;i<=s1+s2;i++)
                {
                    int x=vis[f[i]];
                    int y=sum[i];
                    if(choose[x]==y)
                    {
                        printf("%d
    ",i);
                    }
                }
                printf("end
    ");
            }
            else printf("no
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    This counter can increment, decrement or skip ahead by an arbitrary amount
    LUT4/MUXF5/MUXF6 logic : Multiplexer 8:1
    synthesisable VHDL for a fixed ratio frequency divider
    Bucket Brigade FIFO SRL16E ( VHDL )
    srl16e fifo verilog
    DualPort Block RAM with Two Write Ports and Bytewide Write Enable in ReadFirst Mode
    Parametrilayze based on SRL16 shift register FIFO
    stm32 spi sdcard fatfs
    SPI bus master for System09 (2)
    SQLSERVER中的自旋锁
  • 原文地址:https://www.cnblogs.com/minun/p/10473761.html
Copyright © 2011-2022 走看看