[Explanations] POJ_1417_ (disjoint-set \ backpack

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

1. Transformation: yes said the two sides the same, or different classes (really Cai

There are some changes to the set of topics, within two part collection, now elected from each of the large collection in a small set so that the size of the selected these collections and exactly p1, and there is only one program (in order to determine each who element is the

So do feasibility dp, we record the number of programs, set $ f [i] [j] $ for the first $ i $ a number of programs makes up $ j $, apparently transfer

But to output scheme, due to the requirements of small to large output number, and each small collection, there are a lot of elements, so I do not where to record the transfer, but by $ f [i-1] [j-size] $ program number is a 1, if it is 1, then this is definitely the transfer to, and enumerate all the elements of violence, elected belong to the set

#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\n");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\n",ans[i]);
        printf("end\n");
    }
}

 

Guess you like

Origin www.cnblogs.com/superminivan/p/11545474.html