通过状态压缩DP来做,状态压缩就是将一个状态,用2进制的方法,压缩成一个数。(需要掌握位运算知识和动态规划知识)
代码如下:
#include<cstdio>
#include<cstring>
using namespace std;
const int N = (1<<16)+3;
long long dp[N];
int weapon[N],s[N];
int main() {
int T,n,pcase= 0;
scanf("%d",&T);
while(T--)
{
char str[17];
memset(dp,0,sizeof(dp));
memset(weapon,0,sizeof(weapon));
memset(s,0,sizeof(s));
scanf("%d%s",&n,str);
for(int i = 0 ; i < n ;i++)
{
if(str[i] == '1')
{
weapon[0]+=(1<<i);
}
}
for(int i = 0 ; i < n ;i++)
{
scanf("%s",str);
for(int j = 0 ; j < n ;j++)
{
if(str[j] == '1')
s[i] |= (1<<j); //将每个机器人所持有武器的状态进行压缩到s[i]中
}
}
int all = (1<<n)-1;
for(int i = 1 ; i <= all ;i++)
{
weapon[i] = weapon[0];//将每个武器的状态置为初始武器状态
for(int j = 0 ; j < n;j++)
{
if(i & (1<<j))
{
weapon[i] |= s[j];//如果状态i能杀死机器人,就收购其武器weapon[i]
}
}
}
dp[0] = 1;
for(int i = 0 ; i < all ;i++)
{
for(int j = 0 ; j < n ;j++)
{
if((weapon[i]& (1<<j)) && !(i & (1<<j)))//当前状态无法杀死j-th,但是将其他机器人杀死之后回收武器能杀死j-th
{
dp[i|(1<<j)]+=dp[i];//将状态由i转移到杀死机器人之后的状态
}
}
}
printf("Case %d: %lld\n", ++pcase, dp[all]);
}
}