SPOJ AMR11C Robbing Gringotts [搜索+二分匹配]

题意:有N个贼,M个地窖(N,M<=50)

每个贼有个背包,容量为A1,A2.....AN

每个地窖里有X(X <= 25)件东西,每件东西的价值为B1,B2.。。。BX(<=10000000)

贼都很贪,只会去偷能把自己背包装满的地窖,求最多能偷到多少东西

这个问题要分成两个阶段考虑……

一是谁能偷哪个地窖,问题转化成了01背包问题……由于数据太大,咱们只能搜……

然后,就是匹配问题,KM可以,另外,按照賊的背包容量从大到小顺序匈牙利也行……

于是,对每个地窖,一个Naive的实现:

void dfs(int lv,int num,int deep) {
    if (num > X[N - 1]) return;
    if (lv == deep) {
        visit[num] = mark;
        return;
    }
    dfs(lv + 1, num + A[lv], deep);
    dfs(lv + 1, num, deep);
}

复杂度 2^25,产生了这个地窖所有能拼出来的可能数

然后还得枚举,复杂度 50 * 50 << 25 …… 似乎进入了TLE的节奏……

看了解题报告才明白,Meet-in-middle……也就是DFS一半,哈希起来……然后另一边进去查找……

经过优化,复杂度变成 50 * Max(1 << 15,50 << 10)……

P.S:如果去阿三赛区会不会有拿金进Final的希望……昨天单挑都做了6道,按榜看来已然前12……

第7道差这么个Meet in middle优化……7道前三……

完整代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int N,M;
int adj[55][55];
int A[55];
int X[55];
int visit[10000001];
int deep;
int mark = 1;

int match[55];
bool vv[55];

void dfs(int lv,int num,int deep) {
    if (num > X[N - 1]) return;
    if (lv == deep) {
        visit[num] = mark;
        return;
    }
    dfs(lv + 1, num + A[lv], deep);
    dfs(lv + 1, num, deep);
}

void dfs_2(int lv,int num,int deep,int fa) {
    if (num > X[N - 1]) return;
    if (lv == deep) {
        for (int j = 0; j < N; j++) {
            if (X[j] - num >= 0 && visit[X[j] - num] == mark) {
                adj[j][fa] = X[j];
            }
        }
        return;
    }
    dfs_2(lv + 1, num + A[lv], deep, fa);
    dfs_2(lv + 1, num, deep, fa);
}

bool dfs(int k) {
    if (vv[k]) return false;
    vv[k] = true;
    for (int i = 0; i < M; i++) {
        if (adj[k][i]) {
            int tt = match[i];
            match[i] = k;
            if (tt == -1 || dfs(tt)) return true;
            match[i]=tt;
        }
    }
    return false;
}

int main() {
    int nn; scanf("%d",&nn);
    while (nn--) {
        scanf("%d%d",&N,&M);
        memset(adj,0,sizeof(adj));
        memset(A,0,sizeof(A));
        for (int i = 0; i < N; i++) scanf("%d",X + i);
        sort(X,X + N);
        for (int i = 0; i < M; i++) {
            scanf("%d",&deep);
            for (int j = 0; j < deep; j++) scanf("%d",A + j);
            mark ++;
            if (deep < 15) {
                dfs(0,0,deep);
                for (int j = 0; j < N; j++) {
                    if (visit[X[j]] == mark) {
                        adj[j][i] = X[j];
                    }
                }
            } else {
                dfs(0,0,15);
                dfs_2(15,0,deep,i);
            }
            for (int j = 0; j < N; j++) {
                if (visit[X[j]] == mark) {
                    adj[j][i] = true;
                }
            }
        }
        memset(match,0xff,sizeof(match));
        int ans = 0;
        for (int i = N - 1; i >= 0; i--) {
            memset(vv,0,sizeof(vv));
            if (dfs(i)) ans += X[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

posted on 2012-07-09 15:41  康某-  阅读(373)  评论(0编辑  收藏  举报

导航