google_apactest_round_A_problem_D
先尝试过小数据
题目
有8张卡牌,每个卡牌都可以有不同的等级,每个卡牌的不同等级具有不同的攻击力,可以通过花钱给卡牌充值从而升级,且每次只能升一级,比如可以花1个硬币将卡牌2从1级升级到2级,同时卡牌2可以获得更高的攻击力。现在给定8张卡牌的初始等级Li, 和卡牌的最高等级 Ki, 以及每张卡牌的不同等级的攻击力Aij,以及每张卡牌从等级i升级到等级i+1 时候所需要花的硬币,以及玩家手中现有的总硬币数。
求出玩家通过手中的硬币给卡牌升级,可以使得卡牌获得的攻击力的最大值。
分析
很典型的有限背包问题,只需要构造状态 dp[i][j] (前i种卡牌,通过花j个硬币,可以获得攻击力的最大值),有递推公式
for(level = initial_level; level <= max_level; level ++)
dp[i][j] = max{dp[i][j] + dp[i-1][j - sum_cost] + Attack[i][level]}
其中 sum_cost 是指从initial_level到达当前level所花费的总硬币数目;
比赛的时候以为很简单,小数据通过这种动态规划应该可以过,但是中间遇到了好多bug:
(1)声明dp数组的时候脑残的 声明了dp[8][1005],而其他相关的数组都是声明第一维 至少为10,只有dp数组 第一维被声明成了8,当时一个没注意导致后来不得不在vs中单步debug,而在单步debug的时候发现函数中的某个变量总是莫名其妙的被修改。。百思不得其解,以至于开始怀疑编译器对我不友好== 直到比赛完了之后才发现dp数组的大小声明有误;
麻蛋,这绝对是个大教训!
(2)递归公式很好想,但是边界值在比赛的时候并没有考虑清楚:
边界值应该根据dp状态的定义来谨慎的设置,比如这道题中 dp[i][j] 表示对于前i(1 <= i <= N)种卡牌,使用j个硬币进行增值,所能获得的最大攻击力。于是有
for (int i = 1; i <= N; i++){
attack += A[i - 1][L[i - 1]];
dp[i][0] = attack;
}
同时,在对j的循环中,dp[i][j]的初始值设为 dp[i-1][j] + A[i][initial_level] 表示在对第i种卡牌进行增值的时候,如果不在第i种卡牌花钱增值,此时获得的最大的攻击力为
在前i-1种卡牌上花j个硬币所获得的最大攻击力加上第i种卡牌的初始攻击力.
实现
#include<iostream>
#include<stdio.h>
int dp[10][1005]; int K[10];
int L[10];
int A[10][1005];
int C[10][1005];
int N, M; int getMax(int a, int b){
return a > b ? a : b;
} int Solve(){
memset(dp, 0, sizeof(dp));
int attack = 0;
for (int i = 1; i <= N; i++){
attack += A[i - 1][L[i - 1]];
dp[i][0] = attack;
}
for (int i = 1; i <= N; i++){
int cur_level = L[i-1];
for (int j = 1; j <= M; j++){
int sum_cost = 0, sum_attack = 0;
dp[i][j] = dp[i-1][j] + A[i-1][cur_level];
for (int lev = cur_level; lev < K[i-1]; lev++){
sum_cost += C[i-1][lev];
sum_attack = A[i-1][lev+1];
if (j >= sum_cost)
dp[i][j] = getMax(dp[i][j], dp[i - 1][j - sum_cost] + sum_attack);
}
}
}
return dp[N][M];
} #define FILE_INPUT
int main(){
#ifdef FILE_INPUT
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int T;
scanf("%d", &T);
for (int cas = 1; cas <= T; cas++){
fprintf(stderr, "Case #%d processing\n", cas);
scanf("%d %d", &M, &N);
for (int i = 0; i < N; i++){
scanf("%d %d", &K[i], &L[i]);
for (int j = 1; j <= K[i]; j++){
scanf("%d", &A[i][j]);
}
for (int j = 1; j < K[i]; j++){
scanf("%d", &C[i][j]);
}
}
ll result = Solve();
printf("Case #%d: %lld\n", cas, result);
}
return 0;
}
google_apactest_round_A_problem_D的更多相关文章
随机推荐
- awk用法小结(作者总结)
http://www.chinaunix.net/old_jh/24/691456.html http://wenku.baidu.com/view/ebac4fc658f5f61fb736664d. ...
- SharePoint自动化系列——Manage "Site Subscriptions" using PowerShell
转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/ 你可以将普通的sites加入到你的site subscriptions中,前提是你需要有一个 Te ...
- bash中一些基础知识
bash是linux操作系统的shell.以下是Multi-Perspective Sentence Similarity Modeling论文实现时碰到的一个bash: #!/bin/bash py ...
- 华东交通大学2016年ACM“双基”程序设计竞赛 1002
Problem Description 今天小学弟又训练完了,但是小学弟又不想看球赛,于是小学弟看马赛了.他发现马鞍是一个奇怪的东西.于是小学弟根据马鞍定义了一种马鞍数:在一个二位矩阵中,马鞍数在当前 ...
- 2016年11月19日 星期六 --出埃及记 Exodus 20:10
2016年11月19日 星期六 --出埃及记 Exodus 20:10 but the seventh day is a Sabbath to the LORD your God. On it you ...
- ios项目中引用其他项目复习
ios项目中引用其他开源项目,今天再次复习了,记个备注. 1. 将开源项目的.xcodeproj拖入项目frameworks 2. Build Phases下 Links Binary With Li ...
- Linux用户应知应会的7个‘ls’命令的独特技巧
在前面我们系列报道的两篇文章中,我们已经涵盖了关于‘ls’命令的绝大多数内容.本文时‘ls命令’系列的最后一部分.如果你还没有读过该系列的其它两篇文章,你可以访问下面的链接. Linux中的15个基本 ...
- LuaTinker的bug和缺陷
LuaTinker的bug和缺陷 LuaTinker是一套还不错的C++代码和Lua代码的绑定库,作者是韩国人Kwon-il Lee,作者应该是参考了LuaBind后,为了简化和避免过重而实现的.其官 ...
- SQL 汉字转换成拼音首字母 首字母查
-- ============================================= -- 功能:汉字转换成拼音首字母 首字母查 -- ========================== ...
- FreeSWITCH 1.6关于视频通话的一些测试
简单的测试了一下,暂时没把精力放到这一块. ① 视频编码透传的设置(使用代理模式). 修改internal.xml文件的以下参数: <param name="inbound-proxy ...