• 百度之星资格赛 1003 度度熊与邪恶大魔王 DP 完全背包


      题目链接: http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=774&pid=1003

      题目大意: a[i], b[i] | 0 <= i <= n .................... k[j],  p[j] | 0 <= j <= m,  n个魔王, m中法术方式, 每个法术攻击p[j], 消耗k[j]水晶,   每个魔王a[i]生命, b[i]护甲, 攻击必须先打穿护甲, 求杀死所有魔王的最少水晶数。

      解题思路: dp[i][j] 表示一个魔王血量为i 护甲为 j 的时候, 杀死它需要的最少水晶, 哦对了, 水晶无限,  所以就转换成n个完全背包问题, 再加和。

      代码: 下面我的代码有错, 不知道哪儿错了

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <map>
    #include <cstring>
    #include <iterator>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <deque>
    #include <map>
    
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    
    const int maxn = 1e5+100;
    const int maxm = 1e3 + 100;
    const int maxa = 1e3 + 100;
    const int maxb = 15;
    using namespace std;
    const int INF = 0x3fffffff;
    
    int a[maxn];
    int b[maxn];
    int k[maxm];
    int p[maxm];
    int dp[maxa][maxb]; // dp(i, j)生命值为i , 防御值为 j 的时候消灭它花费最少
    
    
    int main() {
        int n, m;
        while( scanf( "%d%d", &n, &m ) == 2 ) {
            
            int defend = 0;
            int attack = 0;
            int ma = 0;
            for( int i = 1; i <= n; i++ ) {
                scanf( "%d%d", a+i, b+i );
                defend = max( defend, *(b+i) );
                ma = max( ma, *(a+i) );
            }
            for( int i = 1; i <= m; i++ ) {
                scanf( "%d%d", k+i, p+i );
                attack = max( attack, *(p+i) );
            }
            if( attack <= defend ) {
                printf( "-1
    " );
                continue;
            }
            for( int i = 0; i <= ma; i++ ) {
                for( int j = 0; j <= defend; j++ ) {
                    if( i == 0 ) dp[0][j] = 0;
                    else dp[i][j] = INF;
                }
            }
            for( int i = 1; i <= ma; i++ ) {
                for( int j = 0; j <= defend; j++ ) {
                    for( int t = 1; t <= m; t++ ) {
                        if( j > p[t] ) continue;
                        else if( i - (p[t]-j) >= 0 ) {
                            dp[i][j] = min( dp[i][j], dp[i-(p[t]-j)][j]+k[t] );
                        }
                        else dp[i][j] = min( dp[i][j], dp[0][j]+k[t] );
                    }
                }
            }
            long long res = 0;
            for( int i = 1; i <= n; i++ ) {
                res += dp[a[i]][b[i]];
            }
            printf( "%lld
    ", res );
        }
        return 0;
    }
    View Code

      徐文栋的AC代码: 

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int maxn = 100100;
    const int maxm = 1010;
    const int maxp = 10010;
    const int maxa = 1010;
    const int maxb = 11;
    const LL inf = (1LL << 60);
    int n, m;
    int a[maxn], b[maxn], k[maxm], p[maxm];
    LL f[maxa][maxb];
    
    signed main() {
        // freopen("in", "r", stdin);
        while(~scanf("%d %d",&n,&m)) {
            for(int i = 0; i < maxa; i++) {
                for(int j = 0; j < maxb; j++) {
                    f[i][j] = inf;
                }
            }
            for(int i = 0; i < maxb; ++i) f[0][i] = 0;
            int ha = -1, hb = -1;
            for(int i = 1; i <= n; i++) {
                scanf("%d%d",&a[i], &b[i]);
                ha = max(ha, a[i]);
                hb = max(hb, b[i]);
            }
            for(int i = 1; i <= m; i++) scanf("%d%d",&k[i], &p[i]);
    
            for(int i = 1; i <= ha; i++) {
                for(int j = 0; j <= hb; j++) {
                    for(int x = 1; x <= m; x++) {
                        if(j >= p[x]) continue;
                        if(i + j - p[x] > 0) f[i][j] = min(f[i][j], f[i+j-p[x]][j] + k[x]);
                        else f[i][j] = min(f[i][j], f[0][j] + k[x]);
                    }
                }
            }
            LL ret = 0;
            bool flag = 0;
            for(int i = 1; i <= n; i++) {
                if(f[a[i]][b[i]] == inf) {
                    flag = 1;
                    break;
                }
                ret += f[a[i]][b[i]];
            }
            if(flag) puts("-1");
            else printf("%I64d
    ", ret);
        }
        return 0;
    }
    Close
    BestCoder Contest System 2.0
    View Code

      思考: 一开始我想的状态是前i个魔王再加上一个状态来求解, 太天真, 每一个魔王都是独立的, 所以dp方程不管怎么都没有办法转移 ,很难受, 然后我想是不是应该像《劲歌金曲》那样不关心前面的状态, 用滚动数组d[i], i表示血量, 同样面临着无法转移的问题, 后来问了人才知道, 事先预处理每个魔王, 再加和, 自己好蠢。 其实不是蠢的问题, 我想问题就是自己还是没有理清思路, 不能够找到真正和结果相联系的状态, 还得多做题。

  • 相关阅读:
    codeforces 1349 A 思维
    codeforces 1358 D 尺区
    codeforces 1251D 二分+贪心
    codeforces 1260 D 二分
    codeforces 1167B 交互ez
    volatile
    计算多级集合/树/部门树的深度
    Java学习路线-知乎
    day06
    day01_虚拟机与主机之间ip配置
  • 原文地址:https://www.cnblogs.com/FriskyPuppy/p/7294003.html
Copyright © 2020-2023  润新知