HUST 1354 Rubiks

背包。注释写详细了。

本想这样写:每个组内各自做背包,然后组间做背包,但是由于这题M=10000,时间复杂度太大。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<functional>
using namespace std;

const int maxn = 10000 + 10;
int n, m, g;

vector<int>G[20];

int cost[1000 + 10];
int val[1000 + 10];
int y[20];
bool flag[1000 + 10];
int dp1[10000 + 10];
int dp2[10000 + 10];

void init()
{
    memset(flag, 0, sizeof flag);
    for (int i = 1; i <= g; i++) G[i].clear();
}

int main()
{
    while (~scanf("%d%d", &n, &m)){

        for (int i = 1; i <= n; i++) scanf("%d", &cost[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
        scanf("%d", &g);
        init();
        for (int i = 1; i <= g; i++)
        {
            int f;
            scanf("%d", &f);
            for (int j = 1; j <= f; j++)
            {
                int id;
                scanf("%d", &id);
                G[i].push_back(id);
                flag[id] = 1;
            }
            scanf("%d", &y[i]);
        }

        memset(dp1, 0, sizeof dp1);

        //没有组的归为一组
        for (int i = 1; i <= n; i++)
        {
            if (flag[i]) continue;
            for (int j = m; j >= cost[i]; j--)
                dp1[j] = max(dp1[j], dp1[j - cost[i]] + val[i]);
        }

        for (int k = 1; k <= g; k++)
        {
            //此时dp2数组存储了之前的所有组合最优解
            for (int i = 1; i <= m; i++) dp2[i] = dp1[i];

            //接下来假设不买完这个组合内的魔方,这样DP的话事实上也存在买完的组合,但会被之后的dp2更新,所以不存在问题
            for (int s = 0; s < G[k].size(); s++)
            {
                for (int j = m; j >= cost[G[k][s]]; j--)
                {
                    dp1[j] = max(dp1[j], dp1[j - cost[G[k][s]]] + val[G[k][s]]);
                }
            }

            //假设买完,用dp2更新
            int sum_cost = 0, sum_val = y[k];
            for (int s = 0; s < G[k].size(); s++)
            {
                sum_cost = sum_cost + cost[G[k][s]];
                sum_val = sum_val + val[G[k][s]];
            }

            for (int j = m; j >= sum_cost; j--)
            {
                dp2[j] = max(dp2[j], dp2[j - sum_cost] + sum_val);
            }

            //然后dp1和dp2存下最大值
            for (int i = 0; i <= m; i++) dp1[i] = max(dp1[i], dp2[i]);
        }

        printf("%d
", dp1[m]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5193635.html