hihoCoder - 1270 建造基地


时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

在遥远的未来,小Hi成为了地球联邦外空间联合开发工作组的一员,前往一颗新发现的星球开发当地的重金属资源。

为了能够在当地生存下来,小Hi首先要建立一个基地。建立基地的材料可以直接使用当地的石材和富裕的重金属资源。基地建设分为N级,每一级都需要达成K的建设值后才能够完成建设,当前级别的建设值溢出后不会影响到下一级的建设。

小Hi可以产出的重金属资源按照精炼程度分为M级,根据开采的数量和精炼的工艺,可以将获取精炼程度为第i级的重金属资源的成本量化为Ai

在建设第1级基地时,一块精炼度为i的重金属可以提供Bi的建设值,此后基地的级别每提高一级,建设值将除以T并下取整(整除)。

现给定N、M、K、T、A[]和B[],小Hi需要你帮助他计算他完成基地建设的最小成本。

输入

输入包含多组测试数据。

输入的第一行为一个整数Q,表示测试数据的组数。

每组测试数据的第一行为4个整数N、M、K和T,意义如前文所述。

接下来的一行为M个整数,分别表示A1~AM

接下来的一行为M个整数,分别表示B1~BM

对于100%的数据,满足1<=N<=10,1<=M<=100,1<=K,T<=104

对于100%的数据,满足Ai和Bi均为32位整型范围内的正整数

对于100%的数据,满足1<=Q<=10

输出

对于每组测试数据,如果小Hi最终能够完成基地建设,则输出小Hi完成基地建设所需要的最小成本,否则输出“No Answer”。

样例输入
2
2 2 2 2
1 3
1 2
2 2 2 2
1 2
1 1
样例输出
8
No Answer

看了下这道题通过率挺高,以为挺简单的......没想到是考查dp,我dp很烂,简单的还能应对,要自己推转移方程就完全懵逼了。唉,主要还是太菜了吧。

题意读起来有些绕口,涉及变量比较多,多三四遍就理解什么意思了。我第一感觉以为是考“贪心”,先计算M个“单位建设值所需的成本”,然后排序,选一个最小的不为0的建设值矿石,累加他们的和。什么情况下会No Answer?如果M种矿石的建设值都为0的时候,就不能建设成功了。为什么会出现建设值为0呢?因为每建设一层基地需要将M个矿石建设值每个除以T(向下取整),所以就可能出现0了。

这是贪心的想法,然而我提交后是WA...以为是数据范围不够,就把int 换成了long long,然后提交还是WA。

无奈之下看别人题解,居然搜出来大家都是用的完全背包。没办法,硬着头皮看吧,学不会dp总得要学呀!说不定哪天就学会了!看了好几个别人的题解,但...都没怎么看懂,所以又去看完全背包了。

折腾了两个多小时,总算有点明白了...我感觉这道题形式上有点向完全背包,但是需求上不向完全背包,(完全背包是求最大价值,这道题是求最小成本)所以状态转移方程也不太一样吧...


我的代码注释中有自己的理解(也不一定对吧,反正我是这样理解的)还有我参考的一些链接,也贴上。


http://blog.csdn.net/jxust_tj/article/details/50816771

背包问题:

http://www.cppblog.com/tanky-woo/archive/2010/07/31/121803.html

http://www.cnblogs.com/daoluanxiaozi/archive/2012/05/06/2486105.html

#include <cstdio>
#include <string.h>
#include <algorithm>

#define MAX 10000 + 10
#define INF 0x3fffffff

using namespace std;

int A[MAX];
int B[MAX];
long long dp[MAX];

void initData() {
    memset( A, 0, sizeof( A ) );
    memset( B, 0, sizeof( B ) );
}

void downVal( int m, long long t ) {
    for( int i = 1; i <= m; i++ ) {
        B[i] = B[i] / t;
    }
}

int main() {
    int q;
    int n, m, k, t;
    scanf( "%d", &q );

    while( q-- ) {
        initData();
        scanf( "%d%d%d%d", &n, &m, &k, &t );

        for( int i = 1; i <= m; i++ ) {
            scanf( "%d", &A[i] );
        }
        for( int i = 1; i <= m; i++ ) {
            scanf( "%d", &B[i] );
        }

        int level = 1;
        long long sum = 0;
        bool flag = true;

        while( level <= n ) {
            if( level > 1 ) {
                downVal( m, t );
            }

            // dp初始化
            for( int i = 0; i < MAX; i++ ) {
                dp[i] = INF;
            }
            dp[0] = 0;

            for( int i = 1; i <= m; i++ ) {
                for( int j = 0; j <= k; j++ ) {
                    // 当前建设值是j,dp[j]代表当前建设值为j的最小成本
                    // j + B[i]是未来的建设值,dp[j + B[i]]是未来建设值为 ( j + B[i] ) 时的最小成本

                    // 如果未来的建设值大于k,就是题目中说的溢出,那么就把建设值按k计算
                    // 遇到i号矿石,如果选择i号矿石,成本是dp[j] + A[i];
                    // 如果不选i号矿石,成本是dp[k]
                    // 从dp[k]和dp[j] + A[i] 两者选一个小的,代表k时的最小成本
                    if( j + B[i] > k ) dp[k] = min( dp[k], dp[j] + A[i] );


                    // 没有溢出,就正常计算
                    // 遇到i号矿石,如果选择i号矿石,成本是dp[j] + A[i];
                    // 如果不选i号矿石,成本是dp[j + B[i]]
                    // 从两者选一个小的,代表未来建设值为 ( j + B[i] ) 时的最小成本
                    else dp[j + B[i]] = min( dp[j + B[i]], dp[j] + A[i] );
                }
            }

            // 如果建设值为k时的最小成本没有被计算出来,说明没有方案能建设成功
            if( dp[k] == INF ) {
                flag = false;
                break;
            }
            sum = sum + dp[k];
            level++;
        }

        if( flag ) {
            printf( "%lld\n", sum );
        }
        else {
            printf( "No Answer\n" );
        }
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值