UVa:11795 Mega Man's Mission(状态压缩)

思路:集合上的动态规划。

状态转移方程是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;
}


 

你可能感兴趣的:(uva,状态压缩)