UVa11795 - Mega Man's Mission(状压dp)

112 篇文章 0 订阅

题目链接

简介:
每个怪物需要特定的武器击败,每消灭一个怪物将会得到ta的武器
计算可以消灭所有怪物的序列总数

分析:
状压dp
monster[i]:打倒的怪物的状态为i时,获得的武器可以打倒的怪物
arms[i]:拥有的武器为i时,可以打倒的怪物
f[i]:打倒的怪物的状态为i时,可能的方案数

arms数组就是输入数据转化为二进制数
在转移的的时候,枚举下一个打倒的怪物

tip

开ll

#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long

using namespace std;

const int N=70000;
int er[18]={0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536};      
//这里并不是2^i,而是2^(i-1),这样就可以和1~n的怪物对应起来了,第i个怪物对应的就是er[i]
int n;
int arms[N],monster[N];
ll f[N];

void doit()
{
    int i,j,k;
    f[0]=1;
    for (i=0;i<(1<<n)-1;i++)
    {
        if (!f[i]) continue;

        k=monster[i];                         //下一步可以打倒的怪物 
        for (j=1;j<=n;j++)
            if ((k&er[j])!=0&&(i&er[j])==0)   //枚举下一个打倒的怪物 
                f[i|er[j]]+=f[i];
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    for (int cas=1;cas<=T;cas++)
    {
        memset(arms,0,sizeof(arms));
        memset(monster,0,sizeof(monster));
        memset(f,0,sizeof(f));

        scanf("%d",&n);
        char s[20];

        scanf("%s",&s);
        int k=0;
        for (int i=0;i<n;i++)
            if (s[i]=='1') k+=er[i+1];
        arms[0]=k; monster[0]=k;           //拥有第0件武器 

        for (int i=1;i<=n;i++)
        {
            scanf("%s",&s);
            int k=0;
            for (int j=0;j<n;j++)
                if (s[j]=='1') k+=er[j+1];
            arms[er[i]]=k;
        }

        for (int i=1;i<(1<<n);i++)       //打倒怪物k之后就可以获得武器k 
        {
            int k=monster[0];
            for (int j=1;j<=n;j++)
                if (i&er[j]) k|=arms[er[j]];
            monster[i]=k;
        }

        doit();

        printf("Case %d: %lld\n",cas,f[(1<<n)-1]);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值