ZOJ 3623 Battle ships

Battle Ships is a new game which is similar to Star Craft. In this game, the enemy builds a defense tower, which has L longevity. The player has a military factory, which can produce N kinds of battle ships. The factory takes ti seconds to produce the i-th battle ship and this battle ship can make the tower loss li longevity every second when it has been produced. If the longevity of the tower lower than or equal to 0, the player wins. Notice that at each time, the factory can choose only one kind of battle ships to produce or do nothing. And producing more than one battle ships of the same kind is acceptable.

Your job is to find out the minimum time the player should spend to win the game.

Input
There are multiple test cases.
The first line of each case contains two integers N(1 ≤ N ≤ 30) and L(1 ≤ L ≤ 330), N is the number of the kinds of Battle Ships, L is the longevity of the Defense Tower. Then the following N lines, each line contains two integers t i(1 ≤ t i ≤ 20) and li(1 ≤ li ≤ 330) indicating the produce time and the lethality of the i-th kind Battle Ships.

Output
Output one line for each test case. An integer indicating the minimum time the player should spend to win the game.

Sample Input

1 1
1 1
2 10
1 1
2 5
3 100
1 10
3 20
10 100

Sample Output

2
4
5

这道题目的大意是这样的:
有一座血量为L的塔,现在要造一些军舰去推塔,给出n种能造的军舰(军舰的杀伤力不同)(给出的杀伤力代表建造完成后一秒钟军舰能造成的伤害)(同时造这些军舰花费的时间也是不同的)(造军舰的种类与数量不受限制)
给出以上数据,求推塔完成的最短时间。

这其实是一个完全背包问题,塔的血量可以看做背包容量,造军舰花费时长代表物品大小,军舰杀伤力代表物品的价值,又因为军舰种类数目不受限制,所以视为完全背包问题。
但是随着时间的有所限制(物品大小过大大于背包容量)或小杀伤力军舰随时间变化造成的伤害累加,可能存在在某一时间段小价值物品(小杀伤力军舰)造成的伤害更大,因此我觉得不能完全等同于完全背包问题。

因为上面说的杀伤力都是随时间变化的,所求问题解又是求最小时间,所以我们可以考虑计算每一秒钟的最大杀伤力,然后枚举出刚好大于等于塔血量L的最小时间。

因此我们用dp[i]表示i时间的破坏值
状态转移方程为:dp[j]=max(dp[j],dp[j-t[i]]+(j-t[i])*l[i]);
代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int t[35], l[35], dp[400];
int main()
{
    int n, p;
    while(~scanf("%d %d", &n, &p))                       //  输入多组测试数据
    {
        memset(dp, 0, sizeof(dp));                       //每组测试数据开始前都要先进行清零
        for(int i = 0; i < n; ++i)
        {
            scanf("%d %d", &t[i], &l[i]);
        }
        for(int i = 0; i < n; ++i)
        {
            for(int j = t[i]; j <= t[i] + p; ++j)
            {
                dp[j] = max(dp[j], dp[j - t[i]] + (j - t[i]) * l[i]);  //这样的状态转移方程dp数组要开到血量p和最大造军舰时长t[Imax]
            }
        }
        for(int i = 0; i <= 660; i++)                //当血量取到最大且造军舰时间也有的刚好取到最大时,i<=660,但是实际上并不用取到660就会break,这里不用担心会出现数组越界情况。
        {
            if(dp[i] >= p)
            {
                printf("%d\n", i);
                break;
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42785226/article/details/89314632
ZOJ