B-黑石部落
Time Limit: 1000 MS | Memory Limit: 65536 KB |
Total Submissions: 1196 | Accepted: 303 |
Description
20分钟后,在乌瑟尔营地附近的黑石部落内,乌瑟尔派出了谈判的骑士,但活着回来的却只有骑士的马匹。由于兽人仍不愿意投降,乌瑟尔便将指挥权交给了阿尔萨斯,希望由他来组织对黑石兽人的进攻。
阿尔萨斯需要训练自己的部队来对抗兽人。他可以训练的部队有K(K<10)种,第i种部队的一个单位需要消耗G[i]的黄金,而这个部队的战斗力是W[i]。现在阿尔萨斯有一座储量为N(N<15000)的金矿,那么他能训练出的最大战斗力是多少呢?
阿尔萨斯需要训练自己的部队来对抗兽人。他可以训练的部队有K(K<10)种,第i种部队的一个单位需要消耗G[i]的黄金,而这个部队的战斗力是W[i]。现在阿尔萨斯有一座储量为N(N<15000)的金矿,那么他能训练出的最大战斗力是多少呢?
Input
输入包括多组数据,每组数据的第一行是两个正整数N,K。接下来有K行,每行两个正整数,分别是G[i]与W[i]。输入以文件结尾结束。
Output
每行一个数,表示该组数据下阿尔萨斯能训练出的最大战斗力。
Sample Input
10 2
6 12
4 9
6 12
4 9
Sample Output
21
Source
Gardon & Gondar
想了想就是普通的动态规划,从假设只有1黄金开始找最优解,一开始i只允许训练一个单位的时候可以看做0战斗力+训练单位的战斗力,此时可训练单位战斗力的最大值就是最大战斗力。保证开始是最优解后,之后的问题可以拆分成已知训练此单位之前的最大战斗力,判断训练此单位后是否还是最大战斗力,直到黄金达到N为止。
2018/05/09更新:
比如你有两组部队 黄金/战斗力是 4/4 和 4/5,当i=4的时候 dp[4]初始是0,j=0的时候 对应的是4/4,然后判断dp[4](目前4黄金能训练的最大战斗力)和dp[0](已知0黄金能训练的最大战斗力)+4(这个单位的战斗力)的大小,如果这个和大于dp[4]就代表找到了新的最大战斗力,然后j=1时对应4/5。dp[8]的时候 判断的就是dp[8-4](8减这个战斗力需要的黄金数,并且8之前的都是已知的最大战斗力)+这个单位的战斗力。
如果用递归的话,计算5黄金的战斗力,可以拆成1+4或者2+3。拆成1+4的时候 4又可以拆成1+3或者2+2,这样1算了两遍 2算了两遍,再拆2+3 又不知道算了多少遍,动态规划就是倒着来 先算1 2推出来3 4 5
AC代码:
#include<iostream>
#include<algorithm>
using namespace std;
//代表部队,g表示训练一个单位需要消耗的黄金,w表示这个单位的战斗力
struct BD {
int g,w;
};
//用于将军队按消耗黄金从小到大排序
bool cmp(BD a, BD b) {
return a.g<b.g;
}
int main(void) {
int n,k;
while(cin>>n>>k) {
BD bd[10];
for(int i=0; i<k; i++) {
cin>>bd[i].g>>bd[i].w;
}
//排序
sort(bd,bd+k,cmp);
//初始化为0
int dp[15001]= {};
for(int i=1; i<=n; i++) {
for(int j=0;j<k;j++){
//如果黄金足够训练这个单位
if(i-bd[j].g >= 0){
//如果将i-bd[j].g黄金训练得到的最大战斗力
//加上训练此单位的战斗力超过了之前计算的最大战斗力
if(dp[i] < bd[j].w+dp[i-bd[j].g]){
dp[i] = bd[j].w+dp[i-bd[j].g];
}
}
}
}
sort(dp,dp+n+1);
//输出最大值
cout<<dp[n]<<endl;
}
}