HDU 4976 A simple greedy problem. DP
来源:互联网 发布:百度知道评论软件 编辑:程序博客网 时间:2024/04/30 04:33
【题目大意】
玩家A和玩家B在比赛,有n个小兵,每个小兵有一个初始血量hi。A先攻击,他可以选择最多一个小兵,对其造成一点伤害;然后B攻击,B会对所有小兵造成1点伤害。如果小兵的血量到0了,它就死了,造成最后一点伤害的玩家可以得1分。问,A最多得多少分。
【思路】
我们很容易想到一点,如果在一开始所有小兵的血量都不同,那么显然,A可以杀死所有小兵。那么,A的攻击,可以改成两种模式,造成最后一点伤害,或者垫刀,使得小兵的血量尽量不同。而且,我们也可以发现垫刀的优先级要小于得1分的优先级。现在问题的关键是,如果当前没有直接得分策略,我们具体怎么垫刀?最开始,我认为这里应该有一个贪心策略,但是。。。这里是没有贪心策略的。。。
如果我们把小兵按血量排序,假定B不攻击,依次计算,把所有小兵的血量都攻击到不同,每个小兵最终的血量是多少。注意,这里是一定要排序的,比方,如果小兵的血量分别是5 5 4 4 2 1
不排序(x表示不可能)
小兵的血量:5 5 4 4 2 1
垫刀至不同:5 4 3 2 1 x
花费: 0 1 1 1 1 ∞
排序
小兵的血量:5 5 4 4 2 1
垫刀至不同:5 x 4 3 2 1
花费: 0 ∞ 0 1 0 0
显然,排序之后的垫刀花费才是最优策略之一。有了上面的表,如果我们一定要杀死一个小兵,我们会发现,一个最优策略一定是在B攻击次数小于等于“垫刀至不同”的那个血量之前,把这个小兵打到这个血量,然后让B把它打成1血,补最后一刀。这个时候我们终于知道为什么贪心错的了,因为垫刀的优先级受到“花费”和“血量”两个因素影响,“花费”相同,究竟是垫高血量的兵的刀,还是垫低血量的兵,这里是不能说清楚的。
那么,我们可以使用DP解决这个问题,用dp[i][j],表示进行了i组攻击(A攻击一次,B攻击一次,称为一组),A留有j次攻击,最多能杀死的小兵数目。因为一个小兵的最优杀死策略是确定的(A先垫刀到“至不同”的那个血量,B攻击到1血,A补最后一刀),那么DP还是很容易做的。
//#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<cmath>#include<cctype>#include<string>#include<algorithm>#include<iostream>#include<ctime>#include<map>#include<set>using namespace std;#define MP(x,y) make_pair((x),(y))#define PB(x) push_back(x)typedef __int64 LL;//typedef unsigned __int64 ULL;/* ****************** */const LL INF = 1LL<<55;const double INFF = 1e100;const double eps = 1e-8;const LL mod = 10000000007LL;const int NN = 1010;const int MM = 400010;/* ****************** */int re[NN], a[NN], dp[NN][NN];int main(){ int cas, ee = 0; int i, j, t, n, max_n, ans; scanf("%d", &cas); while(cas--) { scanf("%d", &n); memset(re, -1, sizeof(re)); max_n = 0; for(i = 1; i <= n; i ++) { scanf("%d", &a[i]); max_n = max(max_n, a[i]); } sort(a+1, a+1+n); for(i = 1; i <= n; i ++) { for(j = a[i]; j >= 1; j --) { if(re[j] == -1) { re[j] = a[i]; break; } } } memset(dp, -1, sizeof(dp)); dp[0][0] = 0; for(i = 0; i < max_n; i ++) for(j = 0; j <= i + 1; j ++) if(dp[i][j]!=-1) { dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j]); t = j + 1 + i - re[i+1]; if(re[i+1] != -1 && t >= 0) { dp[i+1][t] = max(dp[i+1][t], dp[i][j]+1); } } ans = 0; for(j = 0; j <= max_n + 1; j ++) ans = max(ans, dp[max_n][j]); printf("Case #%d: %d\n", ++ee, ans); } return 0;}
- HDU 4976 A simple greedy problem. DP
- hdoj 4976 A simple greedy problem.【dp】
- hdu-4976-A simple greedy problem.
- hdu 4976 A simple greedy problem.
- 【DP】 HDOJ A simple greedy problem.
- hdu A simple problem
- HDU 4971 A simple brute force problem.(dp)
- HDU - 4971 A simple brute force problem. (DP)
- hdu - 4972 - A simple dynamic programming problem(数学 + dp)
- hdu 1757 A Simple Math Problem(矩阵优化DP)
- hdu 2522 A simple problem
- HDU 4143 A Simple Problem
- HDU 4143 A Simple Problem
- hdu A Simple Math Problem
- HDU 4143 A Simple Problem
- hdu 4143 A Simple Problem
- hdu 4143 A Simple Problem
- hdu 2522 A simple problem
- 『什么找茬』获得PP助手首位推荐
- jsp分页(结合js)
- 读入优化的模板
- poj-1844-Sum
- JS 在 对table 的操作 例如 动态增加行的关键函数
- HDU 4976 A simple greedy problem. DP
- Bootstrap3.0学习第六轮(表单)
- JQuery Camera 插件参数
- 日志分割
- Servlet过滤器
- ListView与ExpandableListView设置分割线 divider
- 拓扑排序
- C语言缺陷和陷阱
- STM32寄存器操作方式学习-GPIO