思路:集合上的动态规划。
状态转移方程是dp[S]=sum{dp[S^p]},其中S表示机器人集合,S^p表示S除去第p个机器人的集合,dp[S]表示消灭集合S内的机器人的顺序总数。当消灭S^p集合内机器人得到的武器可以消灭第p个机器人时,方程成立。
整个过程可以用状态压缩,位运算表示集合完成。但是 判断消灭S^p集合内机器人得到的武器是否可以消灭第p个机器人 这里可以提前预处理一下,用state[S]表示消灭集合S内的机器人之后得到的武器可以消灭的机器人。枚举集合S,处理即可,这里要注意state[S]的初始值不是0,所有的初始值都应该是洛克人自带武器能消灭机器人。
答案要用longlong
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <cmath> #include <queue> #include <algorithm> #define ll long long #define INF 2139062143 #define inf -2139062144 #define MOD 20071027 #define MAXN 131072 using namespace std; int n,get[20]; bool vis[MAXN]; ll dp[MAXN]; int state[MAXN]; ll DP(int S) { if(vis[S]||!S) return dp[S]; vis[S]=true; dp[S]=0; for(int i=0; i<n; ++i) { int p=1<<i; if((S&p)&&(state[S^p]&p)) dp[S]+=DP(S^p); } return dp[S]; } void Init() { int S=1<<n; memset(state,0,sizeof(state)); state[0]=get[0]; for(int i=1; i<S; ++i) { state[i]=get[0]; for(int j=0; j<n; ++j) if(i&(1<<j)) state[i]=state[i]|get[j+1]; } } int main() { int T,kase=0; dp[0]=1; scanf("%d",&T); while(T--) { scanf("%d",&n); char str[20]; memset(get,0,sizeof(get)); for(int i=0; i<=n; ++i) { scanf("%s",str); for(int j=0; str[j]; ++j) if(str[j]=='1') get[i]=get[i]|(1<<j); } Init(); memset(vis,0,sizeof(vis)); printf("Case %d: %lld\n",++kase,DP((1<<n)-1)); } return 0; }