UVA 11795 - Mega Man's Mission(状态压缩DP)

题目链接:点击打开链接

思路:

很容易想到用d[i][s]表示杀死了i个机器人了, 杀死的机器人集合是s的方法数。

转移也很容易我就不说了, 我的转移复杂度是n^2的, 当然你也可以预处理一下某个机器人能被哪些机器人集合杀死, 直接用位运算与来判断, 使得转移变成O(n)

细节参见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <ctime>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
const ll INF64 = ll(1e18);
const int maxn = 17;
int T,n,m, vis[maxn][1<<maxn], kase = 0, init[maxn], able[maxn][maxn];
ll d[maxn][1<<maxn];
ll dp(int i, int s) { // 杀死前i个人,杀死的人的集合为s的方法数
    ll& ans = d[i][s];
    if(i == n) return 1LL;
    if(vis[i][s] == kase) return ans;
    vis[i][s] = kase;
    ans = 0;
    for(int j = 1; j <= n; j++) { // 枚举这次杀死哪个人
        if(s & (1<<j)) continue;
        if(init[j]) { // 如果初始武器就能杀死
            ans += dp(i+1, s | (1<<j));
        }
        else {
            bool ok = false;
            for(int k = 1; k <= n; k++) {
                if(s & (1<<k)) {
                    if(able[k][j]) { ok = true; break; }
                }
            }
            if(ok) ans += dp(i+1, s | (1<<j));
        }
    }

    return ans;
}
char s[maxn];
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d", &n);
        scanf("%s", s+1);
        for(int j = 1; j <= n; j++) {
            int cur = s[j]-'0';
            init[j] = cur;
        }
        for(int i = 1; i <= n; i++) {
            scanf("%s", s+1);
            for(int j = 1; j <= n; j++) {
                int cur = s[j] - '0';
                able[i][j] = cur;
            }
        }
        ++kase;
        ll ans = dp(0, 0);
        printf("Case %d: %lld\n", kase, ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值