题意: 给出有几个怪兽以及初始的可以打的怪兽的二进制序列。为1的就是可以打的为0的就是不可以打的。 打死一只怪兽后你就可以用它的武器去打特定的怪兽。 问最多有几种方案。
分析:看数据大小估计是状压dp,S[i]表示的是当死的怪兽的状态为i的时候所获得的武器可以打死哪些怪兽。weapon[i]表示当打死怪兽i的时候所可以获得的武器。 dp[i]表示当死的怪兽的状态为i的时候最多可以有几种方案。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1<<17;
long long dp[N];
int S[N],weapon[18],T,n;
char robot[18],init[18];
int main() {
scanf("%d",&T);
int cas = 0;
while(T--) {
scanf("%d %s",&n,init);
memset(S,0,sizeof(S));
memset(weapon,0,sizeof(weapon));
memset(dp,0,sizeof(dp));
for(int i = 0; i < strlen(init); i++) {
if(init[i] == '1')
S[0] |=(1 << i);
}
for(int i = 0; i < n; i++) {
scanf("%s",robot);
for(int j = 0; j < strlen(robot); j++)
if(robot[j] == '1')
weapon[i] |= (1 << j);
}
for(int i = 0; i < (1 << n); i++) {
S[i] = S[0];
for(int j = 0; j < n ; j++) {
if((i & (1 << j)))
S[i] |= weapon[j];
}
}
dp[0] = 1;
for(int i = 0; i < (1 << n); i++) {
if(dp[i] == 0)
continue;
for(int j = 0;j < n; j++) {
if((S[i] &(1 << j))!= 0 && (i &(1 << j)) == 0)
dp[i | (1 << j)] += dp[i];
}
}
printf("Case %d: %lld\n", ++cas,dp[(1 << n) - 1]);
}
return 0;
}