ZOJ3812--We need Medicine

题目大意:给出n个物品,每个物品有两个属性w[i]和t[i],然后,有q组查询,每组查询有两个数字m和s,从所有物品中挑出一些,使得w之和等于m,t之和等于s,每个物品只能挑一件,如果有这样的方案,就输出挑选的物品,没有的话,则输出No solution!。


分析:01背包的加强版。参考别人的代码的。传送门http://blog.csdn.net/qian99/article/details/39138329


代码:

#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;

typedef unsigned long long ull;
const int maxn = 444;
const int maxm = 51;
int dp[200010][52];
int w[maxn], t[maxn];
ull f[200010];
map<ull, int> mp;

int main() {
    for(int i = 1; i <= maxm+1; i++)
        mp[(ull)1<<(i-1)] = i;
    int T;
    scanf("%d", &T);
    while(T--) {
        int n, q;
        scanf("%d%d", &n, &q);
        memset(dp, 0, sizeof(dp));
        memset(f, 0, sizeof(f));
        f[0] = 1;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &w[i], &t[i]);
            for(int j = 200000; j >= t[i]; j--) {
                ull S = f[j];
                f[j] |= (f[j-t[i]]<<w[i]) & ((ull)(1<<(maxm+1))-1);
                for(ull k = S^f[j]; k; k &= k-1) {
                    ull x = (k^(k-1)) & k;
                    dp[j][mp[x]-1] = i;
                }
            }
        }
        while(q--) {
            int m, s;
            scanf("%d%d", &m, &s);
            if(!dp[s][m]) printf("No solution!\n");
            else {
                while(m) {
                    int p = dp[s][m];
                    printf("%d%c", p, m == w[p] ? '\n' : ' ');
                    m -= w[p];
                    s -= t[p];
                }
            }
        }
    }
    return 0;
}


你可能感兴趣的:(ZOJ3812--We need Medicine)