经典DP——夜狼

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的技巧之一,可以避免处理相邻更新带来的复杂性。在 ij 区间内,若 k 是最后一个狼,则其他狼都已被击败,此时 k 的左右邻居只可能是 k-1k+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,约为 200^3 = 8 \times 10^6,可以接受。


总结

这道题非常考验对区间DP模型的掌握。核心思路是确定一个区间内“最后被击败”的狼,然后通过子区间的最优解推导整段的最优解。这种技巧在很多博弈类、树形结构或链状结构的DP问题中都有应用。

如果你也喜欢这种题型,推荐练习:石子合并、矩阵连乘、括号匹配等经典区间DP题目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_gxd_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值