Description
夜狼,也被称为黑狼,是非常大型的有力量的狼。据说大部分夜狼起源于德拉诺。
夜狼看起来像普通的狼,但这些生物的大小几乎是普通狼的两倍。这些强大的野兽,长 8 - 9 尺,重 600 - 800 磅,是最有名的兽人坐骑。这些狼和人一样高,长着长牙,看起来像是能咬断铁棍一样。他们有火红色的眼睛,皮毛则是斑驳的黑色或灰色。野狼一般在卡利姆多和穆尔戈尔北部地区繁衍生息。
夜狼是高效的猎群者,他们捕杀任何猎物,喜欢成群结队地攻击,找准时机包围并从侧翼攻击敌人。
——Wowpedia,魔兽世界的维基百科。
马特,一个来自东方王国的冒险家,遇到了一群夜狼。N 只夜狼站成一排(从左到右按照 1 到 N 的顺序编号),马特必须打败他们才能生存。
一旦马特打败一只夜狼,他将受到相当于狼当前攻击的伤害,作为群居动物,每一只夜狼可以为相邻的夜狼增加攻击 bi。因此,每只狼的当前攻击力有两部分组成,基本攻击 ai 和当前相邻狼提供的额外攻击。攻击的增加是暂时的,一旦一只狼被打败,它周围的狼将不再受到额外的攻击,然而它周围的两只狼(如果还活着)就会变得相邻。
例如,有 3 只夜狼站在一排,他们的基本攻击 ai 分别是(3,5,7),提供给别人的额外攻击分别为(8,2,0)。因此,他们目前的攻击是(5,13,9)。如果马特先击败第二只狼,他将受到 13 点伤害,剩下的狼攻击变为(3,15)。
作为一位机智的冒险家,马特可以决定他击败的夜狼的顺序。因此,他想知道他必须承受最少多少伤害才能打败所有的狼。
Format
Input
第一行一个整数 n(2 ≤ n ≤ 200);
第二行包含 n 个整数 ai(0 ≤ ai ≤ 1000000),表示每只夜狼的基本攻击。
第二行包含 n 个整数 bi(0 ≤ bi ≤ 50000),表示每只夜狼可以提供的额外攻击。
Output
一行,一个整数,为马特受到的最小伤害。
Samples
输入数据 1
3
3 5 7
8 2 0
输出数据 1
17
输入数据 2
10
1 3 5 7 9 2 4 6 8 10
9 4 1 2 1 2 1 4 5 1
输出数据 2
74
思路
题目分析
这是一道典型的区间动态规划问题,关键在于如何设计状态表示和状态转移。
我们注意到每次击杀一只狼,马特都会承受这只狼当前的攻击力(包括基本攻击 + 邻居提供的加成)。由于击杀某只狼会改变剩余狼之间的邻接关系,因此击杀顺序会显著影响总伤害。
我们尝试从“区间”的角度考虑。设 dp[i][j]
表示击败区间 [i,j]
内所有夜狼所承受的最小总伤害(不包括i和j,但i和j可以给别的狼增加能量)。每次我们选择在某个区间 [i,j]
内先击杀第 k
只狼,那么可以将问题分成两个子问题 [i,k-1]
和 [k+1,j]
,再加上当前击杀第 k
只狼时的伤害。
状态表示
dp[i][j]
:击败区间[i,j]
的所有狼所承受的最小总伤害(不包括i和j,但i和j可以给别的狼增加能量)。- 对于某个
k ∈ [i,j]
,考虑它作为最后一个被击败的狼。
为什么要设为“最后一个”?这是区间DP的技巧之一,可以避免处理相邻更新带来的复杂性。在 i
到 j
区间内,若 k
是最后一个狼,则其他狼都已被击败,此时 k
的左右邻居只可能是 k-1
和 k+1
是否还在区间中。
状态转移方程
for(int len=2;len<=n;len++){//长度一般从2开始,长度为1的是初始化的
for(int i=1;i+len-1<=n+1;i++){
int j=i+len-1;
for(int k=i;k<j;k++){
dp[i][j]=...//状态转移
}
}
}
初始化
当 i == j
时,只剩下一只狼,它没有邻居,攻击力就是自身的基本攻击力 a[i]
。
dp[i][i]=a[i];
代码
#include<bits/stdc++.h>
using namespace std;
int n,j,a[300],b[300],dp[300][300];
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int len=2;len<=n+2;len++){
for(int i=0;i+len-1<=n+2;i++){//区间DP
j=i+len-1;
if(i+1==j)continue;//中间没狼怎么赋能
dp[i][j]=1e9;
for(int k=i+1;k<j;k++){//不包括i和j,从i+1到j-1
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[k]+b[i]+b[j]);
}
}
}
cout<<dp[0][n+1];//输出
return 0;
}
复杂度分析
- 时间复杂度:O(n³)
- 三重循环:长度、起点、分割点。
- 空间复杂度:O(n²)
- 使用了一个二维DP数组来记录最优解。
考虑到 n ≤ 200,约为 ,可以接受。
总结
这道题非常考验对区间DP模型的掌握。核心思路是确定一个区间内“最后被击败”的狼,然后通过子区间的最优解推导整段的最优解。这种技巧在很多博弈类、树形结构或链状结构的DP问题中都有应用。
如果你也喜欢这种题型,推荐练习:石子合并、矩阵连乘、括号匹配等经典区间DP题目。