OJ3RD 1121 战士科高校的劣等生 - DP

来源:互联网 发布:红黑树 c语言实现 编辑:程序博客网 时间:2024/04/30 07:28

题目描述

我是一名战士科高校的劣等生,
我只有一个技能那就是瞬间把任何一个敌人直接杀掉!
在某次执行任务时,有一排敌人挡在我的面前;
正当我准备将敌人逐个击破时发现敌人的反击很强烈;
每当我瞬秒一个敌人的时候,它旁边的敌人总会对我造成即时的反击伤害;
杀掉一个敌人之后,其他敌人会补上位置!!!
这导致我不可以无伤地干掉他们这一群军队了;
但我可以感知到每个敌人的攻击力;
可是我脑子有限,知道了攻击力也不知道如何选择进攻顺序才能使自己受到的伤害最小
所以,大家帮帮我这个劣等生吧~

输入

多组测试数据。
测试数据为2行:
第一行为一个整数N ( 1 <= N <= 200 ),表示有N个敌人站成一排
第二行为用空格隔开的N个整数,表示每个敌人的攻击力( 1<=攻击力<=1000 )

输出

输出一行,为战士受到的最小伤害

输入样例

2
1 100

输出样例

1

用dp[i][j]表示清除从第i个到第j个敌人所要受到的最小伤害,为了方便循环假设存在第0号和第(N+1)号敌人,将第0号和第(N+1)号的攻击力设成0

每次攻击都要受相邻两敌人的伤害,那么清除这个区间内敌人时,最后一次所受伤害一定来自区间左外和右外的头一个敌人,

那么问题就明朗了,假设最后清除的那个编号为 (k+1),(k+1) 从i取到j,打擂台取最小伤害加上a[i-1]和a[j+1]就行

dp[i][j] = min{dp[i][k]+dp[k+2][j] ,k从i取到j-2,dp[i+1][j],dp[i][j-1]} + a[i-1] + a[j+1]

虽然状态转移方程这样写,但是要明白状态转移的顺序是按i和j的差来的,差为1和2很容易初始化,把差放在第一层循环,从3到N-1,里层i从1取到(N-差)

#include <cstdio>#include <iostream>#include <algorithm>using namespace std;int N;int a[202];int dp[202][202];int min_attack(int l, int r){int min = 0x3f3f3f3f;for (int k = l; k < r - 1; ++k){min = min < (dp[l][k] + dp[k + 2][r]) ? min : (dp[l][k] + dp[k + 2][r]);}min = min < dp[l + 1][r] ? min : dp[l + 1][r];min = min < dp[l][r - 1] ? min : dp[l][r - 1];return min;}int main(){while (~scanf("%d", &N)){for (int i = 1; i <= N; ++i)scanf("%d", &a[i]);a[0] = 0;a[N + 1] = 0;for (int i = 1; i <= N; ++i)dp[i][i] = a[i - 1] + a[i + 1];for (int i = 1; i < N; ++i)dp[i][i + 1] = min(dp[i][i], dp[i + 1][i + 1]) + a[i - 1] + a[i + 2];for (int j = 2; j < N; ++j)for (int i = 1; i <= N - j; ++i)dp[i][i + j] = min_attack(i, i + j) + a[i - 1] + a[i + j + 1];printf("%d\n", dp[1][N]);}return 0;}


0 0