dp

题意:

        给你 n 张卡片,总共可以消耗的法力值,求最多可以造成多少伤害, 卡片分为2种,一种是魔法卡,使用后可以使所有的连环卡的费用全部减1,另一种是连环卡,因魔法卡的使用可以使其费用减1,问最终最多可以造成多少的伤害

思路分析 :

      比赛的时候大脑短路了,基本不愿意去想东西了,导致题目没有出来,这个题就是一个 01背包,但是增加了一个限制条件,所以我们多增加一维表示到当前位置,所使用的魔法卡的数量,但是呢,还有一个很关键的地方,就是我们要先对卡片经行一个排序的预处理,这样在搞 dp的时候,才不会对后续有任何的影响,排序的时候,优先使用魔法卡,然后两者都是的卡,剩下的卡就随意了。

代码示例:(未测试)

#define ll long long
const int maxn = 1e6+5;
const int mod = 1e9+7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;

int n, w;

struct node
{
    int w, x, p1, p2;
    
}pre[505];
int dp[505][505][505];
int cnt = 0;

bool cmp1(node a, node b){
    if (a.p1 == b.p1) return a.p2 < b.p2;
    return a.p1 > b.p1;
}

bool cmp2(node a, node b){
    if (a.w == b.w) return a.x > b.x;
    return a.w < b.w;    
}

void fun(){
    
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= w; j++){
            for(int k = 0; k <= min(i, cnt); k++){ // 使用魔法卡
                if (pre[i].p1 && !pre[i].p2) { // 1 0
                    if (j >= pre[i].w && k) 
                        dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-pre[i].w][k-1]+pre[i].x);
                    else dp[i][j][k] = dp[i-1][j][k]; 
                }
                else if (pre[i].p1 && pre[i].p2){ // 1 1
                    int cost = max(pre[i].w-k+1, 0);
                    //if (i == 2 && j == 2) printf("cost = %d
", cost);
                    if (j >= cost && k){
                        dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-cost][k-1]+pre[i].x);
                    }
                    else dp[i][j][k] = dp[i-1][j][k];             
                }
                else if (!pre[i].p1 && pre[i].p2){ // 0 1
                    int cost = max(pre[i].w-k, 0);
                    if (j >= cost && k){
                        dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-cost][k]+pre[i].x);
                    }
                    else dp[i][j][k] = dp[i-1][j][k];
                }
                else { // 0 0
                    if (j >= pre[i].w){
                        dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-pre[i].w][k]+pre[i].x); 
                    }
                    else dp[i][j][k] = dp[i-1][j][k];
                }
                //printf("+++%d %d %d =  %d  
",i, j, k, dp[i][j][k]);
            }        
        }
    }
}

void init(){
    int pos1 = -1, pos2 = -1;
    
    for(int i = 1; i <= n; i++){
        if (pre[i].p1 && !pre[i].p2) {
            pos1 = i;
            break;
        }
    }
    for(int i = n; i >= 1; i--){
        if (pre[i].p1 && !pre[i].p2) {
            pos2 = i;
            break;
        }
    }
    if (pos1 != -1) sort(pre+pos1, pre+pos2+1, cmp2);
    
    pos1 = pos2 = -1;
    for(int i = 1; i <= n; i++){
        if (pre[i].p1 && pre[i].p2) {
            pos1 = i;
            break;
        }
    }
    for(int i = n; i >= 1; i--){
        if (pre[i].p1 && pre[i].p2) {
            pos2 = i;
            break;
        }
    }
    if (pos1 != -1) sort(pre+pos1, pre+pos2+1, cmp2);
    
    pos1 = pos2 = -1;
    for(int i = 1; i <= n; i++){
        if (!pre[i].p1 && !pre[i].p2) {
            pos1 = i;
            break;
        }
    }
    for(int i = n; i >= 1; i--){
        if (!pre[i].p1 && !pre[i].p2) {
            pos2 = i;
            break;
        }
    }
    if (pos1 != -1) sort(pre+pos1, pre+pos2+1, cmp2);
    
    pos1 = pos2 = -1;
    for(int i = 1; i <= n; i++){
        if (!pre[i].p1 && pre[i].p2) {
            pos1 = i;
            break;
        }
    }
    for(int i = n; i >= 1; i--){
        if (!pre[i].p1 && pre[i].p2) {
            pos2 = i;
            break;
        }
    }
    if (pos1 != -1) sort(pre+pos1, pre+pos2+1, cmp2);
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    
    cin >> n >> w;
    for(int i = 1; i <= n; i++){
        scanf("%d%d%d%d", &pre[i].w, &pre[i].x, &pre[i].p1, &pre[i].p2);
        if (pre[i].p1 == 1) cnt++;
    }
    sort(pre+1, pre+1+n, cmp1);
    init(); 
    for(int i = 1; i <= n; i++){
        printf("%d%d%d%d
", pre[i].w, pre[i].x, pre[i].p1, pre[i].p2);
    }
    memset(dp, 0x8f, sizeof(dp)); 
    for(int j = 0; j <= w; j++) {
        dp[0][j][0] = 0;
    }
    fun();
    int ans = 0;
    for(int i = 0; i <= cnt; i++) ans = max(ans, dp[n][w][i]);
    printf("%d
", ans);    
    return 0;
}
/*
4 3
1 3 0 1
1 0 0 0
3 3 1 1
3 4 1 0

3 3
3 3 1 1
2 3 1 1
1 3 1 1

3 4
3 10 1 1
30 400 1 1
4 200 1 1

5 5
6 50 1 1
3 30 0 1
3 3 1 0
3 200 0 0
3 6 1 0

6 4
1 3 1 0
2 5 0 0
1 2 0 1
2 2 1 1
3 4 0 1
1 1 1 0
*/
东北日出西边雨 道是无情却有情
原文地址:https://www.cnblogs.com/ccut-ry/p/9121110.html