题意:阅读题目情景第一反应——炉石传说 ,说有一群狼每只狼都有自己的基础攻击,还有对两边随从的攻击力加成(orz....这不就是炉石里的恐狼前锋?如下图)
现需要制定一个消灭顺序,使得自己受到的总伤害最小(每消灭一只狼受到其基础攻击和来自两边狼对其攻击加成的伤害)
思路:首先因为最后要全部消灭,所以每只狼的基础攻击都会抗一遍,所以只需考虑如何使受到攻击加成伤害最小,一般思路是贪心,从加成最大的开始消灭,但是不对!举出一组例子就明显了,比如加成7 8 2 从加成最大的开始杀并不是最优的,所以贪心暂时pase掉。靠谱的解法——区间dp:
状态: f[i][j]表示从i到j全干掉最小伤害(要考虑i-1,j+1的影响,即不是完全独立)
递推关系: 要算f[i][j]时,枚举这一段中最后一个被消灭的k,这样就将之分为两个子段的和以及最后干掉第k个时两边的影响,即:
f[i][j]=Min(f[i][k-1]+f[k+1][j]+b[i-1]+b[j+1])
实现:最外层循环枚举区间长度l,里层循环枚举开始位置i,最里层循环枚举最后一个被消灭位置k
代码如下:
#include<cstdio>
#include<math.h>
#include<algorithm>
using namespace std;
int n,a,b[210],f[210][210];
int calf(int i,int j)
{
return (i<=j)? f[i][j]:0;
}
int calb(int i)
{
return (i>=0 && i<n)? b[i]:0;
}
int main()
{
int t,T,x;
scanf("%d",&T);
for(t=1;t<=T;t++)
{
scanf("%d",&n);
a=0;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
a+=x;
}
for(int i=0;i<n;i++) scanf("%d",&b[i]);
for(int l=0;l<n;l++) //长度l
for(int i=0;i+l<n;i++) //起点i
{
int j=i+l; //终点j
f[i][j]=calf(i,i-1)+calf(i+1,j);
for(int k=i+1;k<=j;k++)
{
f[i][j]=min(f[i][j],calf(i,k-1)+calf(k+1,j));
}
f[i][j]+=calb(i-1)+calb(j+1);
}
printf("Case #%d: %d\n",t,a+f[0][n-1]);
}
return 0;
}