动态规划五

复健Day4

动态规划(五)区间DP

1.石子合并

https://www.acwing.com/problem/content/284/

这是区间DP的模板题

这道题看似和果子合并很相像,于是我们想到贪心,但是这是行不通的

因为我们每次只能合并相邻的两堆,可以在纸上画一下样例,显然是不对的

f[l][r]表示把从lr合并成一堆的最小代价:f[l,r]=f[l][k]+f[k+1][r]+s[r]s[l1]

边界:f[i][i]=0

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 310
#define inf 0x3f3f3f3f
using namespace std;

int f[maxn][maxn];
int s[maxn];
int a[maxn];

int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=n;i++) f[i][i]=0;
	for(int len=2;len<=n;len++)//先枚举长度,再枚举左端点,最后枚举中间分割点
	{
		for(int l=1;l+len-1<=n;l++)
		{
			int r=l+len-1;
			for(int k=l;k<r;k++)
			{
				f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
			}
		}
	}
	printf("%d\n",f[1][n]);
	return 0;
}

2.环形石子合并

https://www.luogu.com.cn/problem/P1880

展环为链即可

注意最后输出不是f[1][n]g[1][n],而是要枚举起点,取最大值和最小值

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 310
#define inf 0x3f3f3f3f
using namespace std;

int f[maxn][maxn];
int g[maxn][maxn];
int s[maxn];
int a[maxn];

int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
	for(int i=1;i<=2*n;i++) s[i]=s[i-1]+a[i];
	memset(f,0x3f,sizeof(f));
	memset(g,-0x3f,sizeof(g));
	for(int i=1;i<=2*n;i++) f[i][i]=0,g[i][i]=0;
	for(int len=2;len<=n;len++)
	{
		for(int l=1;l+len-1<=2*n;l++)
		{
			int r=l+len-1;
			for(int k=l;k<r;k++)
			{
				f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
				g[l][r]=max(g[l][r],g[l][k]+g[k+1][r]+s[r]-s[l-1]);
			}
		}
	}
	int maxx=0,minv=inf;
	for(int i=1;i<=n;i++) minv=min(minv,f[i][i+n-1]),maxx=max(maxx,g[i][i+n-1]);
	printf("%d\n%d\n",minv,maxx);
	return 0;
}

3.能量项链

https://www.luogu.com.cn/problem/P1063

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 210
using namespace std;

int f[maxn][maxn];
int a[maxn];

signed main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		a[i+n]=a[i];
	}
	//for(int i=1;i<=2*n;i++) f[i][i]=0;
	for(int len=2;len<=n;len++)
	{
		for(int l=1;l+len-1<=2*n;l++)
		{
			int r=l+len-1;
			for(int k=l;k<r;k++)
			{
				f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]+a[l]*a[k+1]*a[r+1]);
			}
		}
	}
	int maxx=0;
	for(int i=1;i<=n;i++) maxx=max(maxx,f[i][i+n-1]);
	printf("%d\n",maxx);
	return 0;
}

注意l的终止条件是l+len1<=2×n,如果我写成l2×n,会可能让数组越界,而且时间复杂度也变高了

posted on   dolires  阅读(5)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示