• [题解]POJ_1417_(并查集背包


    https://blog.csdn.net/qq_34731703/article/details/54603652

    1.转化:yes表示双方同类,否则不同类(真的蔡

    题目变为有一些集合,内部分两个集合,现在要从每个大集合里选出一个小集合使得选出的这些集合大小之和恰好为p1,且只能有一种方案(这样才能确定每个元素是谁

    所以不用可行性dp,我们记录方案数,设$f[i][j]$为前$i$个拼成$j$的方案数,转移显然

    但是要输出方案,由于要求从小到大输出编号,而且每个小集合里有很多元素,所以不记录从哪转移,而是看$f[i-1][j-size]$方案数是否为1,如果是1的话肯定是从这转移来的,然后暴力枚举所有元素,选出属于这个集合的即可

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=1009;
    int n,p1,p2;
    int fa[maxn],d[maxn],w[2][maxn],v[maxn],p[maxn];
    inline int find(int x){
        if(x==fa[x])return x;
        int rt=find(fa[x]);
        d[x]^=d[fa[x]];
        return fa[x]=rt;
    }
    inline void unionn(int x,int y,int k){
        int xx=find(x),yy=find(y);
        if(xx==yy)return;
        fa[xx]=yy;
        d[xx]=d[x]^d[y]^k;
    }
    int f[maxn][maxn];
    int main(){
        while(scanf("%d%d%d",&n,&p1,&p2) && (n+p1+p2)){
            for(int i=1;i<=p1+p2;i++)fa[i]=i;
            memset(d,0,sizeof(d));
            memset(v,0,sizeof(v));
            memset(w,0,sizeof(w));
            memset(f,0,sizeof(f));
            char s[10];
            for(int i=1,x,y;i<=n;i++){
                scanf("%d%d%s",&x,&y,s);
                if(s[0]=='y')unionn(x,y,0);
                else unionn(x,y,1);
            }
            //暴力找每个小集合 
            int cnt=0;
            for(int i=1;i<=p1+p2;i++)
            if(!v[i]){
                ++cnt;
                int ff=find(i);
                for(int j=i;j<=p1+p2;j++)
                if(find(j)==ff && !v[j])v[j]=1,w[d[j]][cnt]++;
                p[cnt]=ff;
            }
            //dp 
            f[0][0]=1;
            for(int i=1;i<=cnt;i++){
                int flr=min(w[0][i],w[1][i]);
                for(int j=p1;j>=flr;j--){
                    if(f[i-1][j-w[0][i]]){
                        f[i][j]+=f[i-1][j-w[0][i]];
    //                    from[i][j]=j-w[0][i];
                    }
                    if(f[i-1][j-w[1][i]]){
                        f[i][j]+=f[i-1][j-w[1][i]];
    //                    from[i][j]=j-w[1][i];
                    }
                }
            }
            if(f[cnt][p1]!=1){
                printf("no
    ");continue;
            }
            //统计答案 
            int ans[maxn],tot=0,mj=p1;
            for(int i=cnt;i>=1;i--)
            if(f[i-1][mj-w[0][i]]==1){
                for(int j=1;j<=p1+p2;j++)
                if(find(j)==p[i] &&d[j]==0)ans[++tot]=j;
                mj-=w[0][i];
            }
            else{
                for(int j=1;j<=p1+p2;j++)
                if(find(j)==p[i] && d[j]==1)ans[++tot]=j;
                mj-=w[1][i];
            }
            sort(ans+1,ans+1+tot);
            for(int i=1;i<=tot;i++)printf("%d
    ",ans[i]);
            printf("end
    ");
        }
    }
  • 相关阅读:
    使用 Spring data redis 结合 Spring cache 缓存数据配置
    Spring Web Flow 笔记
    Linux 定时实行一次任务命令
    css js 优化工具
    arch Failed to load module "intel"
    go 冒泡排序
    go (break goto continue)
    VirtualBox,Kernel driver not installed (rc=-1908)
    go运算符
    go iota
  • 原文地址:https://www.cnblogs.com/superminivan/p/11545474.html
Copyright © 2020-2023  润新知