算法进阶指南-动态规划-区间dp

1.石子合并
题目链接
在这里插入图片描述
题解:对于合并一个长度为2的区间,假设该区间以a沙堆作为起点,我们用dp[a][a+1]来表示它的价值,那么 d p [ a ] [ a + 1 ] = d p [ a ] [ a ] + d p [ a + 1 ] dp[a][a+1]=dp[a][a]+dp[a+1] dp[a][a+1]=dp[a][a]+dp[a+1][a+1]+value[a]+value[a+1].对于一个区间长度为3的, d p [ a ] [ a + 2 ] = m i n ( d p [ a ] [ a ] + d p [ a + 1 ] [ a + 2 ] , d p [ a ] [ a + 1 ] + d p [ a + 2 ] [ a + 2 ] ) + v a l u e [ a ] + v a l u e [ a + 1 ] + v a l u e [ a + 3 ] dp[a][a+2]=min(dp[a][a]+dp[a+1][a+2],dp[a][a+1]+dp[a+2][a+2])+value[a]+value[a+1]+value[a+3] dp[a][a+2]=min(dp[a][a]+dp[a+1][a+2],dp[a][a+1]+dp[a+2][a+2])+value[a]+value[a+1]+value[a+3]
对于后面的加法我们可以通过前缀和作预处理

代码:

#include <iostream>
#include <math.h>

using namespace std;
const int N = 310;
int a[310];
int dp[N][N];
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		dp[i][i] = 0;
	}
	for (int i = 1; i <= n; i++)
		a[i] += a[i - 1];

	for (int l = 2; l <= n; l++)
		for (int b = 1; b <= n - l + 1; b++)
		{
			int tail = b + l - 1;
			if (b != tail)
				dp[b][tail] = 9999999;
			for (int k = b; k < tail; k++)
				dp[b][tail] = min(dp[b][tail], dp[b][k] + dp[k + 1][tail] + a[tail] - a[b - 1]);
		}
	cout << dp[1][n] << endl;
}


2.Polygon
题目链接
在这里插入图片描述
题解:对于一个环,我们通常喜欢,把它断开循环一次
在这里插入图片描述
,假设我们断的是1和n,那么我们求1~ n进行合并的最大值,假设短的是1和2,那么我们求2 ~ n+1进行合并的最大值.因为我们不确定是从那断开所以每一种情况都要考虑,那么这题就转换成了和第一题相似的问题,只不过进行合并的方式有所不同.

代码:

#include <iostream>
#include <queue>
#include <math.h>
#include <string.h>
using namespace std;
const int N = 51;
int dian[2 * N];
char bian[2 * N];
int maxs[3 * N][3 * N], mins[3 * N][3 * N];

int suan(int a, char b, int c)
{
	if (b == 't')
	{

		return a + c;
	}
	else
	{
		return a * c;
	}
}

int main()
{
	int n;
	cin >> n;

	for (int i = 1; i <= n; i++)
	{
		cin >> bian[i] >> dian[i];
		bian[n + i] = bian[i];
		dian[n + i] = dian[i];
	}
	int most = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= 2 * n - i + 1; j++)
		{
			if (i == 1)
			{
				maxs[j][j] = dian[j];
				mins[j][j] = dian[j];
				maxs[n + j][n + j] = dian[j];
				mins[n + j][n + j] = dian[j];
			}

			else
			{
				maxs[j][j + i - 1] = -32767;
				mins[j][j + i - 1] = 32767;
				for (int k = j + 1; k - j + 1 <= i; k++)
				{
					int z = suan(maxs[j][k - 1], bian[k], maxs[k][j + i - 1]);
					int x = suan(mins[j][k - 1], bian[k], mins[k][j + i - 1]);
					int c = suan(mins[j][k - 1], bian[k], maxs[k][j + i - 1]);
					int v = suan(maxs[j][k - 1], bian[k], mins[k][j + i - 1]);
					maxs[j][j + i - 1] = max(maxs[j][j + i - 1], max(z, max(x, max(c, v))));
					mins[j][j + i - 1] = min(mins[j][j + i - 1], min(z, min(x, min(c, v))));

					if (i == n)
					{
						most = max(most, maxs[j][j + n - 1]);
					}
				}
			}
		}
	cout << most << endl;

	for (int i = 1; i <= n; i++)
	{
		if (maxs[i][i + n - 1] == most)
			cout << i << " ";
	}
}


3.金字塔
题目链接
在这里插入图片描述
题解:
在这里插入图片描述
(借用 作者:心里没有一点ac数 的图)
代码:

#include<iostream>
#include<math.h>
#include<string>
#include<string.h>
using namespace std;
typedef long long ll;
const int mod=1e9;
const int N=310;
ll dp[N][N];


int main()
{
    string a;
    cin>>a;
    int n=a.length();
    for(int i=1;i<=a.length();i+=2)
        for(int l=0;l<=n-i+1;l++)
        {
           int tail=l+i-1;
           if(i==1)dp[l][l]=1;
           else if(a[l]==a[tail])
           {
                 for(int k=l;k<tail;k=k+2)
                 {  if(a[k]==a[tail])
                      dp[l][tail]=(dp[l][tail]+dp[l][k]*dp[k+1][tail-1])%mod;

                 }
           }
        }

        cout<<dp[0][a.length()-1]<<endl;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值