poj1417

并查集+dp,一切尽在代码中。大笑

参考链接:http://blog.youkuaiyun.com/shahdza/article/details/7779230

(今天,队友买的核桃到了,帮忙带了一斤,超级好吃,我以为队友沉浸在核桃的美味中了,结果队友说她在思考,好尴尬害羞

2015.10.5:

核桃快吃完了。

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define N 1210//p1,p2分别小于300

int fa[2*N];
int cou[N];
int dp[N][N];
int fro[N][N];
int mark[N];

int get_root(int x){
    if(fa[x]==x){
        return x;
    }
    else{
        fa[x]=get_root(fa[x]);

        return fa[x];
    }
}

int main(){
    int n,p1,p2;
    int m;
    int x,y;
    char reply[10];

    while(scanf("%d%d%d",&n,&p1,&p2)!=EOF&&!(n==0&&p1==0&&p2==0)){
        m=p1+p2;
        for(int i=1;i<=m;i++){//分清n和m的含义
            fa[i]=i;
            cou[i]=1;
        }
        for(int i=m+1;i<=2*m;i++){
            fa[i]=i;
            cou[i]=0;
        }

        for(int i=0;i<n;i++){
            scanf("%d%d%s",&x,&y,reply);

            int ra=get_root(x);
            int ram=get_root(x+m);
            int rb=get_root(y);
            int rbm=get_root(y+m);

            if(reply[0]=='y'&&ra!=rb){
                fa[ra]=rb;
                fa[ram]=rbm;
                cou[rb]+=cou[ra];
                cou[ra]=0;
                cou[rbm]+=cou[ram];
                cou[ram]=0;
            }
            else if(reply[0]=='n'&&ram!=rb){
                fa[ra]=rbm;
                fa[ram]=rb;
                cou[rbm]+=cou[ra];
                cou[ra]=0;
                cou[rb]+=cou[ram];
                cou[ram]=0;
            }
        }

        /*int cou=0;//样例3错了,说明即使最后剩了不只两个集合,也可能正确的推出好人和坏人
        int fcou=0,fnum=-1;
        int scou=0,snum=-1;
        bool pd=true;

        for(int i=1;i<=m;i++){
            int rt=get_root(i);

            if(cou==0){
                fnum=rt;
                fcou++;
                cou++;
            }
            else if(cou==1){
                if(fnum==rt){
                    fcou++;
                }
                else{
                    snum=rt;
                    scou++;
                    cou++;
                }
            }
            else if(cou==2){
                if(fnum==rt){
                    fcou++;
                }
                else if(snum==rt){
                    scou++;
                }
                else{
                    pd=false;
                    break;
                }
            }
        }

        if(pd==false||p1==p2){
            printf("no\n");
        }
        else{
            int num;

            if(fcou==p1){
                num=fnum;
            }
            else{
                num=snum;
            }

            for(int i=1;i<=m;i++){
                int rt=get_root(i);

                if(rt==num){
                    printf("%d\n",i);
                    p1--;
                }
            }
            printf("end\n");
        }*/

        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        int froloca=0;
        for(int i=1;i<=m;i++){
            if(cou[i]==0/*&&cou[i+m]==0*/){//如果cou[i]==0,那么cou[i+m]==0,代表i所在的组不用i来表示
                continue;
            }
            else{
                for(int j=0;j<=m;j++){
                    if(dp[froloca][j]){
                        dp[i][j+cou[i]]+=dp[froloca][j];
                        dp[i][j+cou[i+m]]+=dp[froloca][j];
                        fro[i][j+cou[i]]=i;
                        fro[i][j+cou[i+m]]=i+m;
                    }
                    //printf("%d %d %d %d %d %dha\n",i,j+cou[i],j+cou[i+m],dp[froloca][j],i,i+m);
                    //printf("%d %d %dhe\n",i,j+cou[i],fro[i][j+cou[i]]);
                    //printf("%d %d %dhe\n",i,j+cou[i+m],fro[i][j+cou[i+m]]);
                }
                froloca=i;
            }
        }

        /*for(int i=1;i<=m;i++){
            printf("%d %d\n",get_root(i),get_root(i+n));
        }*/

        //printf("%d\n",dp[m][p1]);

        /*for(int i=0;i<=m;i++){
            for(int j=0;j<=m;j++){
                printf("%d ",dp[i][j]);
            }
            printf("\n");
        }*/

        if(dp[froloca][p1]!=1){
            printf("no\n");
        }
        else{
            memset(mark,false,sizeof(mark));
            int fronum=p1;

            for(int i=froloca;i>0;i--){
                if(cou[i]==0/*&&cou[i+m]==0*/){
                    continue;
                }
                else{
                    //printf("%d %d %d %dha\n",fronum,fro[i][fronum],cou[fro[i][fronum]],p1);
                    mark[fro[i][fronum]]=true;
                    //printf("%d\n",fro[i][fronum]);
                    fronum=fronum-cou[fro[i][fronum]];
                    //printf("%dhe\n",fronum);
                    //printf("%dha\n",fronum);
                }
            }

            /*for(int i=1;i<=m;i++){
                if(mark[i]){
                    printf("%dha\n",i);
                }
            }*/

            for(int i=1;i<=m;i++){
                int rt=get_root(i);
                //printf("%d %d %d\n",i,rt,cou[i]);

                if(mark[rt]){
                    printf("%d\n",i);
                }
            }
            printf("end\n");
        }
    }

    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值