zoj3738 Buy the Pets(人、猫、狗 DP)

47 篇文章 0 订阅

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5120

有N个人要买宠物,有M只猫和P只狗,人的编号是1~N,猫的编号是N+1~N+M,狗的编号是N+M+1~N+M+P;每个人都买一只猫和一只狗;

然后有Q条限制,表明对应编号的人和猫(过敏)或是猫和狗(打架)不能在一起,然后问有多少种购买方案使得N个人都满足,所谓的满足就是这个人买的猫和狗不打架,同时人不会对买的猫造成过敏。

dp[i][j]表示取到第i个人第j种状态时的方案数。当前猫和狗取了哪几只以二进制压缩在第二维中。

1240MS。还有10MS更优解法。

#include<bits/stdc++.h>   
using namespace std;  
int x[45][45];  
long long dp[2][(1<<21)];   
int main(){  
   int n,m,p,a,b,nn;  
   while(~scanf("%d %d %d",&n,&m,&p)){  
       memset(x,0,sizeof(x));  
       scanf("%d",&nn);  
       while(nn--){  
           scanf("%d %d",&a,&b);  
           x[a][b]=1;x[b][a]=1;
       }  
       for(int i=0;i<(1<<(m+p));++i)
           dp[0][i]=0;
       //为什么memset(dp[0],0,(1<<(m+p)))就错了? 
       dp[0][0]=1;  
       int q=1;  
       for(int i=1;i<=n;i++){  
           for(int j=0;j<(1<<(m+p));++j)
               dp[q][j]=0; 
           for(int j=0;j<(1<<(m+p));++j){  
               if(dp[1-q][j]==0)  
                   continue;  
               for(int k=0;k<m;k++){  
                   if(x[i][n+(k+1)]||(j&(1<<k))) //人猫过敏或者状态j里这只猫已经被取过了
                       continue;  
                   for(int l=m;l<m+p;l++){  
                       if(x[n+(k+1)][n+(l+1)]||j&(1<<l)||j+(1<<k)+(1<<l)>=(1<<(m+p)))  //猫狗过敏或者状态j里这只狗已经被取过了
                           continue;  
                       dp[q][j+(1<<k)+(1<<l)]+=dp[1-q][j]; 
                   }  
               }  
           }  
           q=1-q;  
       }  
       long long ans=0;  
       for(int j=0;j<(1<<(m+p));j++)  
           ans+=dp[1-q][j];  
       printf("%lld\n",ans);  
   }  
   return 0;  
}  


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值