POJ 1417 True Liars(路径压缩并查集+DP背包问题)

来源:互联网 发布:nba2konline强退软件 编辑:程序博客网 时间:2024/05/13 02:41

POJ 1417 True Liars(路径压缩并查集+DP背包问题)

http://poj.org/problem?id=1417

题意:

        给出p1+p2个人,其中p1个是好人,p2个是坏人。然后有一些关系 ,a说b是好人(坏人).其中没有矛盾的,判断是否有唯一解判断哪些人是好人,哪些人是坏人。

        其中比较重要的是,好人总说真话,坏人总说假话(这句话的特殊意义)。不会存在矛盾情况。请问你是否存在唯一解,如果存在请输出唯一解。

分析:

        如果A说B是好人,那么A与B是同一类人。如果A说B是坏人,那么A与B不同类。(想想为什么是这样)

        所以原题所给的每句话就是一条路径压缩并查集的关系,那么我们最终合并所有关系可以得到cnt个连通分量且每个分量中节点的相互关系(同类or异类)我们都知道。

        好,现在假设有cnt个连通分量,第一个分量有x1与y1个两类人(我们不知道到底x1那些人是好人还是y1那些人是好人),第二个分量有x2与y2个两类人...所以我们现在想知道是否只有一种方式让我们从第一分量中抓X1(或Y1)个人来,从第二分量中抓X2(或Y2)人来...直到每个分量都抓一类人时,正好抓了p1个人。

        如果只有1种方式实现上面的目的,那么就有唯一解。记录DP的每次选择最后输出即可。

        令d[i][j]表示取完前i个分量后正好j人的方法数,我们最后要求的是看d[cnt][p1]是否==1?

        DP转移方程:dp[i][j]=sum{ dp[i-1][j-bag[i][0]]+dp[i-1][j-bag[i][1]] }

 AC代码:

<span style="font-size:18px;">#include<cstdio>#include<cstring>#include<map>using namespace std;const int MAXN=1000;int bag[MAXN][2];//bag[i][0]表示第i(重新编号了)个连通分量的0类人的个数,bag[i][1]表1类人map<int,int> mp;//用来将老的连通分量编号映射bag中的新编号int cnt;//一共有cnt个分量int insert(int x,int b)//连通分量x,与x的关系是b(0表示同类,1表示异类){    if(mp.find(x)==mp.end())mp[x]=++cnt;    bag[mp[x]][b]++;//该分量的b类人加1    return mp[x];}int F[MAXN];int v[MAXN];//表示i与根的关系int findset(int i){    if(F[i]==-1)return i;    int temp= findset(F[i]);    v[i] =(v[i]+v[F[i]])%2;    return F[i]=temp;}void bind(int i,int j,int temp){    int fa=findset(i);    int fb=findset(j);    if(fa!=fb)    {        F[fb]=fa;        v[fb]=(v[i]+v[j]+temp)%2;    }}int d[MAXN][310];//DPint main(){    int n,p1,p2;    while(scanf("%d%d%d",&n,&p1,&p2)==3)    {        if(n==0&&p1==0&&p2==0)break;        cnt=0;        mp.clear();        memset(bag,0,sizeof(bag));        memset(F,-1,sizeof(F));        memset(v,0,sizeof(v));        memset(d,0,sizeof(d));        while(n--)        {            int a,b,temp;            char str[10];            scanf("%d%d%s",&a,&b,str);            if(str[0]=='y')                temp=0;            else if(str[0]=='n')                temp=1;            int fa=findset(a);            int fb=findset(b);            if(fa!=fb)//不同分量                bind(a,b,temp);;        }        for(int i=1;i<=p1+p2;i++)//将1到p1+p2所有点重新编号        {            int fi=findset(i);            insert(fi,v[i]);        }        d[0][0]=1;//初值        for(int i=1;i<=cnt;i++)//连通分量编号从1到cnt        {            for(int j=0;j<=p1;j++)            {                if( j>=bag[i][0] )                    d[i][j] = d[i-1][j-bag[i][0]];                if( j>=bag[i][1] )                    d[i][j] += d[i-1][ j-bag[i][1] ];            }        }        //printf("###%d\n",d[cnt][p1]);        if(d[cnt][p1]==1)//能区分出        {            int j=p1;            int choose[MAXN];//choose[i]=1/0表示第i(重新编号)个连通分量选择第0类还是选第1类            memset(choose,-1,sizeof(choose));            for(int k=cnt;k>=1;k--)//逆推找出choose            {                if( d[k][j] == d[k-1][j-bag[k][0]] )                {                    choose[k]=0;                    j=j-bag[k][0];                }                else if( d[k][j] == d[k-1][j-bag[k][1]] )                {                    choose[k]=1;                    j=j-bag[k][1];                }            }            for(int i=1;i<=p1+p2;i++)            {                int fa=findset(i);//找出分量的编号fa                int num=mp[fa];//找出fa重新编号后的编号 num                if(v[i]==choose[num])                    printf("%d\n",i);            }            printf("end\n");        }        else        {            printf("no\n");        }    }    return 0;}</span>

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 外阴长了个包出血很痛怎么办 腿上烫成泡了泡泡破了掉皮了怎么办 脚上的脚气小泡泡破了怎么办 吃鸡使用改名卡改名符号怎么办 爱派平板电脑密码忘了怎么办 电脑优酷下载总显示未知错误怎么办 文本文档打开时显字符丢失怎么办 系统文件过大无法放进u盘怎么办 淘宝上买的密钥激活不了怎么办 苹果手机玩游戏屏幕卡住不动怎么办 电脑系统安装好一排英文字怎么办 赴日签证申请表写错了怎么办 不知道自己想要做什么工作怎么办 三星note4微信出现闪退怎么办 魅蓝note6手机自动闪退怎么办 苹果6s系统内存占用量过大怎么办 想在一年通过会计初级和中级怎么办 特殊岗位退休档察写的力工怎么办 面试时期望工资说低了。怎么办 面试时期望薪资写低了怎么办 高考后比一模差了80分怎么办 戒了烟我不习惯没有你我怎么办 没有你我不习惯没有你我怎么办 做什么都没兴趣嫌麻烦怎么办 快递还在路上就确认收货了怎么办 微信显示时间与手机不符怎么办 微信提示银行卡预留手机不符怎么办 得了湿疹后吃了海鲜严重了怎么办 看到小区街道乱扔的垃圾你会怎么办 去韩国干服务员不会讲韩语怎么办 华为手机键盘变英文字母大了怎么办 淘宝申请售后卖家余额不足怎么办 发票名称少写了一个字怎么办 微博数量与实际数量不一致怎么办 在淘宝中要买的商品卖完了怎么办 病因写错了保险不报销怎么办? 上学期间保险名字写错了怎么办 塑料盆上的商标纸撕了胶怎么办 川航买机票名字错了两个字怎么办 买机票护照号码填错了怎么办 换旅行证给孩子改名字怎么办