当前位置:网站首页>动态规划(区间dp)
动态规划(区间dp)
2022-07-03 10:16:00 【Dαīsч】
(一)、基础
1、特点:
(1)、合并:将两个或多个部分进行整合,能将问题分解为能两两合并的形式
(2)、求解:对整个问题设最优值,枚举合并点,将问题分解为左右两个部分,最后合并两个部分的最优值得到原问题的最优值
(3)、复杂度:大多为 O ( n 3 ) O(n^3) O(n3),因此区间 d p dp dp的数据范围一般在 100 100 100左右
2、套路:第一层循环枚举区间长度,第二层循环枚举区间左端点,右端点也固定下来,第三层循环枚举区间的分割点
状态表示: d p [ i ] [ j ] dp[i][j] dp[i][j]表示区间 [ i , j ] [i,j] [i,j]能得到的最大(小)价值
状态转移: d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k + 1 ] [ j ] + c o s t ) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+cost) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+cost)
(二)、例题
1、石子合并
题意:在一个环上有 n n n个石子 a 1 , a 2 . . . . . . a n a_1,a_2......a_n a1,a2......an,进行 n − 1 n-1 n−1次合并操作,每次操作将相邻的两堆合并成一堆,能获得新的一堆中的石子数量的和的得分,求最大得分和最小得分( 1 ≤ n ≤ 100 1\leq n\leq 100 1≤n≤100)
题解:考虑不在环上的情况,那么我们可以把两堆石子合并看出成两个区间合并,代价即为两个区间内的石子数量的和
状态表示: d p [ i ] [ j ] dp[i][j] dp[i][j]代表区间 [ i , j ] [i,j] [i,j]石子堆能得到的最大(小)得分
状态转移方程: d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k + 1 ] [ j ] + s u m ( i , j ) ) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum(i,j)) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum(i,j))
为了处理环,我们把n个石子堆变为 2 ∗ n 2*n 2∗n个石子堆,这样对 2 ∗ n 2*n 2∗n个石子堆进行区间 d p dp dp,然后取从 i i i往后 n n n个石子堆能得到的最大值即可
int dp1[maxn][maxn], dp2[maxn][maxn];
int a[maxn], pre[maxn];
void solve()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = n + 1; i <= 2 * n; i++)
{
a[i] = a[i - n];
}
n *= 2;
for (int i = 1; i <= n; i++)
{
pre[i] = pre[i - 1] + a[i];
}
memset(dp1, 0x3f, sizeof(dp1));
for (int i = 1; i <= n; i++)
{
dp1[i][i] = 0;
}
for (int sz = 1; sz < n; sz++)
{
for (int i = 1, j; (j = i + sz) <= n; i++)
{
for (int k = i; k < j; k++)
{
dp1[i][j] = min(dp1[i][j], dp1[i][k] + dp1[k + 1][j]);
dp2[i][j] = max(dp2[i][j], dp2[i][k] + dp2[k + 1][j]);
}
dp1[i][j] += pre[j] - pre[i - 1];
dp2[i][j] += pre[j] - pre[i - 1];
}
}
n /= 2;
int ans1 = inf, ans2 = 0;
for (int i = 1; i <= n; i++)
{
ans1 = min(ans1, dp1[i][i + n - 1]);
ans2 = max(ans2, dp2[i][i + n - 1]);
}
cout << ans1 << '\n' << ans2 << '\n';
}
2、能量项链
题意:有一能量珠,串前一颗能量珠的头标记为 m m m,尾标记为 r r r,后一颗能量珠的头标记为 r r r,尾标记为 r r r,则聚合后释放的能量为 m ∗ n ∗ r m*n*r m∗n∗r,新产生的珠子的头标记为 m m m,尾标记为 n n n,给定 n n n个数, 第 i i i个数为第 i i i颗珠子的头标记( 1 ≤ i ≤ m 1\leq i\leq m 1≤i≤m)例如 2 3 5 10 2\ 3\ 5\ 10 2 3 5 10对应的石子就是 ( 2 , 3 ) ( 3 , 5 ) ( 5 , 10 ) ( 10 , 2 ) (2,3)(3,5)(5,10)(10,2) (2,3)(3,5)(5,10)(10,2),如果合并第一个和最后一个石子那么获得能量是 10 ∗ 2 ∗ 3 10*2*3 10∗2∗3,求将所有珠子成一个能得到的最大能量( 4 ≤ n ≤ 100 4\leq n\leq 100 4≤n≤100)
题解:类似于石子合并
状态表示: d p [ i ] [ j ] dp[i][j] dp[i][j]代表区间 [ i , j ] [i,j] [i,j]能获得的最大能量
状态转移: d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k + 1 ] [ j ] + a [ i − 1 ] ∗ a [ k ] ∗ a [ j ] ) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+a[i-1]*a[k]*a[j]) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+a[i−1]∗a[k]∗a[j])
ll dp[maxn][maxn];
ll a[maxn];
void solve()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
a[n + i] = a[i];
}
a[0] = a[n];
n *= 2;
for (int sz = 2; sz <= n; sz++)
{
for (int i = 1, j; (j = i + sz - 1) <= n; i++)
{
for (int k = i; k < j; k++)
{
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + a[i-1] * a[k] * a[j]);
}
}
}
ll ans = 0;
for (int i = 1; i <= n / 2; i++)
{
ans = max(ans, dp[i][i + n / 2 - 1]);
}
cout << ans << '\n';
}
3、括号匹配对数
题意:寻找括号匹配对数,不可重复使用
题解:
状态表示: d p [ i ] [ j ] dp[i][j] dp[i][j]表示区间 [ i , j ] [i,j] [i,j]内有多少对匹配的括号
状态转移:两种转移 d p [ i ] [ j ] = d p [ i + 1 ] [ j − 1 ] + m a t c h ( i , j ) dp[i][j]=dp[i+1][j-1]+match(i,j) dp[i][j]=dp[i+1][j−1]+match(i,j)从稍小的区间转移,并且判断边界是否匹配
d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k + 1 ] [ j ] + m a t c h ( k , k + 1 ) ) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+match(k,k+1)) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+match(k,k+1))从分界点转移,并且判断分界点是否匹配
int dp[maxn][maxn];
char s[maxn];
int match(int a, int b)
{
return s[a] == '(' && s[b] == ')' || s[a] == '[' && s[b] == ']';
}
void solve()
{
while (cin >> s + 1)
{
if (s[1] == 'e' && s[2] == 'n' && s[3] == 'd' && s[4] == '\0')
break;
memset(dp, 0, sizeof(dp));
int n = strlen(s + 1);
for (int sz = 2; sz <= n; sz++)
{
for (int i = 1, j; (j = i + sz - 1) <= n; i++)
{
dp[i][j] = dp[i + 1][j - 1] + match(i, j);
for (int k = i; k < j; k++)
{
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + match(k, k + 1));
}
}
}
cout << dp[1][n] * 2 << '\n';
}
}
边栏推荐
- AMS series - application startup process
- Have you learned the new technology to improve sales in 2021?
- 程序员的创业陷阱:接私活
- ORACLE 11G 单机冷备数据库
- Probability theory: application of convolution in calculating moving average
- 【Proteus仿真】74HC154 四线转12线译码器组成的16路流水灯
- I have been doing software testing for three years, and my salary is less than 20K. Today, I put forward my resignation
- 如何让让别人畏惧你
- 2022-07-02: what is the output of the following go language code? A: Compilation error; B:Panic; C:NaN。 package main import “fmt“ func mai
- The manuscript will be revised for release tonight. But, still stuck here, maybe what you need is a paragraph.
猜你喜欢

Intel 13th generation core flagship exposure, single core 5.5ghz

Solution: jupyter notebook does not pop up the default browser

Summary of interview questions (2) IO model, set, NiO principle, cache penetration, breakdown avalanche

在职美团测试工程师的这八年,我是如何成长的,愿技术人看完都有收获

(二)进制

Clion debug

A simple method of adding dividing lines in recyclerview

Unity移动端游戏性能优化简谱之 画面表现与GPU压力的权衡

Error installing the specified version of pilot

Résumé des questions d'entrevue (2) Modèle io, ensemble, principe NiO, pénétration du cache, avalanche de rupture
随机推荐
My understanding of testing (summarized by senior testers)
Analysis of JMM memory model
Crawl with requests
Ext file system mechanism principle
How did I grow up in the past eight years as a test engineer of meituan? I hope technicians can gain something after reading it
如何:配置 ClickOnce 信任提示行为
Encapsulate a koa distributed locking middleware to solve the problem of idempotent or repeated requests
面试题总结(2) IO模型,集合,NIO 原理,缓存穿透,击穿雪崩
The element form shows the relationship between elementary transformation and elementary matrix
Function details of CorelDRAW graphics suite 2022
FL Studio 20无限试用版水果编曲下载
How to clean up v$rman_ backup_ job_ Details view reports error ora-02030
进程与线程
ORACLE 11G 单机冷备数据库
Oracle收回权限 & 创建角色
【obs】封装obs实现采集的基础流程
ExecutorException: Statement returned more than one row, where no more than one was expected.
How to become a senior digital IC Design Engineer (1-3) Verilog coding syntax: Verilog behavior level, register transfer level, gate level (abstract level)
Lecture 1 number field
Google Earth Engine(GEE)——GHSL 全球人口网格数据集250米分辨率