UVa11795

来源:互联网 发布:淘宝网开直通车的要求 编辑:程序博客网 时间:2024/05/22 11:56

题目链接

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

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

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

tip

开ll

#include<cstdio>#include<cstring>#include<iostream>#define ll long longusing 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;}
原创粉丝点击