zoukankan      html  css  js  c++  java
  • POJ-1417 (带权并查集+计数dp)

    题目:传送门

    思路:带权并查集,分出若干个集合,每个集合缩成两个权值,如果唯一存在 每个集合中的一个权值相加后等于天使的个数,那么就能够判断出哪些是天使。这里我们可以用一个DP(i,j)表示前i个集合能组成 j 的方案数,最后记录一下路径,把每个集合的一些点加入答案中。 需要注意的是这里的初值是只有DP(0,0)才有意义,因为是恰好组成 j 的方案数,因此不能用滚动数组优化。

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cctype>
    #include<functional>
    #include<cmath>
    #include<algorithm>
    #pragma GCC optimize(2)
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<double,double> pdd;
    const int N=1e3+5;
    const int inf=0x3f3f3f3f;
    const int mod=998244353;
    const double eps=1e-9;
    const long double pi=acos(-1.0L);
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define fi first
    #define se second
    #define pb push_back
    #define mk make_pair
    #define mem(a,b) memset(a,b,sizeof(a))
    LL read()
    {
        LL x=0,t=1;
        char ch;
        while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return x*t;
    }
    int n,p1,p2,tot;
    int w0[N],w1[N],f[N],v[N],dp[N][N],p[N];
    int getf(int x)
    {
        if(x!=f[x])
        {
            int t=f[x];
            f[x]=getf(f[x]);
            v[x]+=v[t];
            v[x]%=2;
        }
        return f[x];
    }
    inline int init()
    {
        tot=0;
        for(int i=1;i<=p1+p2;i++) f[i]=i,v[i]=0;
        mem(dp,0);
        mem(w0,0);
        mem(w1,0);
    }
    int main()
    {
        while(scanf("%d%d%d",&n,&p1,&p2)!=EOF&&(n||p1||p2))
        {
            init();
            for(int i=1;i<=n;i++)
            {
                int x=read(),y=read();
                char z[5];
                scanf("%s",z);
                int t=z[0]=='n';
                int fx=getf(x),fy=getf(y);
                if(fx!=fy)
                {
                    v[fy]=(-v[y]+t+v[x]+2)%2;
                    f[fy]=fx;
                }
            }
            for(int i=1;i<=p1+p2;i++)
            {
                if(i!=getf(i)) continue;
                int r=i;
                p[++tot]=r;
                for(int j=1;j<=p1+p2;j++)
                {
                    if(r!=getf(j)) continue;
                    if(v[j]%2==v[r]%2) w0[tot]++;
                    else w1[tot]++;
                }
            }
            dp[0][0]=1;
            for(int i=1;i<=tot;i++)
                for(int j=p1;j>=0;j--)
                {
                    if(j>=w0[i]) dp[i][j]+=dp[i-1][j-w0[i]];
                    if(j>=w1[i]) dp[i][j]+=dp[i-1][j-w1[i]];
                }//不能用滚动数组优化,因为只有(0,0)为1;
            if(dp[tot][p1]!=1)
            {
                printf("no
    ");
                continue;
            }
            int k=p1;
            vector<int> ans;
            for(int i=tot;i&&k;i--)
            {
                if(k>=w0[i]&&dp[i-1][k-w0[i]]==1)
                {
                    k-=w0[i];
                    int r=p[i];
                    for(int j=1;j<=p1+p2;j++)
                        if(r==getf(j)&&v[j]==0) ans.pb(j);
                }
                else if(k>=w1[i]&&dp[i-1][k-w1[i]]==1)
                {
                    k-=w1[i];
                    int r=p[i];
                    for(int j=1;j<=p1+p2;j++)
                        if(r==getf(j)&&v[j]==1) ans.pb(j);
                }
            }
            sort(ans.begin(),ans.end());
            for(int i=0;i<ans.size();i++) printf("%d
    ",ans[i]);
            printf("end
    ");
        }
        return 0;
    }
    /*
    4 4 2
    1 2 yes
    3 6 no
    4 3 no
    1 5 yes
    */
    AC
  • 相关阅读:
    手把手教你测之二——有信,一款网络电话
    DroidPilot V2.1 手写功能特别版
    《移动应用自动化测试现状与方向研讨会》视频
    手把手教你测——上网快鸟
    DroidPilot AutoRunner新版宣传视频
    DroidPilot参展2012香港贸发局国际资讯科技博览会
    视频: DroidPilot
    注意!用户使用自己的adb,版本必须是Android SDK 10以上
    部分厂家用户反映USB连接问题,是厂家修改了adb导致,解决方法:
    软件简单介绍
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12583645.html
Copyright © 2011-2022 走看看