Part 4.3 区间动态规划

2024-06-18 05:52
文章标签 动态 规划 part 区间 4.3

本文主要是介绍Part 4.3 区间动态规划,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[NOI1995] 石子合并

题目描述

在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N N N 堆石子合并成 1 1 1 堆的最小得分和最大得分。

输入格式

数据的第 1 1 1 行是正整数 N N N,表示有 N N N 堆石子。

2 2 2 行有 N N N 个整数,第 i i i 个整数 a i a_i ai 表示第 i i i 堆石子的个数。

输出格式

输出共 2 2 2 行,第 1 1 1 行为最小得分,第 2 2 2 行为最大得分。

样例 #1

样例输入 #1

4
4 5 9 4

样例输出 #1

43
54

提示

1 ≤ N ≤ 100 1\leq N\leq 100 1N100 0 ≤ a i ≤ 20 0\leq a_i\leq 20 0ai20

解题思路

dp1[i][j]表示从第i个位置到第j个位置的石子合并的最小值,dp2[i][j]表示从第i个位置到第j个位置的石子合并的最大值。
dp1[i][j]=min(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])
dp2[i][j]=max(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])
sum是前缀和数组,预先处理。
注意题目中提到石子是循环摆放,对于带循环问题的一般处理方法是把数组开两倍大小,前n个位置正常摆放,后n个位置再摆放一便,这样方便模拟循环。

代码实现

#include<iostream>
using namespace std;
#define MAX_N 100
int sum[2*MAX_N+5];
int dp1[2*MAX_N+5][2*MAX_N+5];
int dp2[2*MAX_N+5][2*MAX_N+5];
int main()
{int n;cin>>n;for(int i=1;i<=n;i++){cin>>sum[i];sum[i+n]=sum[i];sum[i]+=sum[i-1];sum[i+n]+=sum[i+n-1];}for(int i=n+1;i<=2*n;i++)sum[i]+=sum[n];for(int l=2;l<=n;l++){for(int i=1;i<=2*n-l+1;i++){int j=i+l-1;dp1[i][j]=0x7ffff;for(int k=i;k<j;k++){dp1[i][j]=min(dp1[i][j],dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]); dp2[i][j]=max(dp2[i][j],dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]);}}}int ans1=0x7ffff,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<<endl<<ans2<<endl;return 0;
}

[USACO16OPEN] 248 G

题面翻译

给定一个 1 × n ( 2 ≤ n ≤ 248 ) 1\times n\,(2\le n\le248) 1×n(2n248) 的地图,在里面玩 2048,每次可以合并两个相邻且相同的数(数值范围 1 ∼ 40 1\sim 40 140),问序列中出现的最大数字的值最大是多少。注意合并后的数值并非加倍而是 + 1 +1 +1,例如 2 2 2 2 2 2 合并后的数值为 3 3 3

题目描述

Bessie likes downloading games to play on her cell phone, even though she doesfind the small touch screen rather cumbersome to use with her large hooves.

She is particularly intrigued by the current game she is playing.The game starts with a sequence of N N N positive integers ( 2 ≤ N ≤ 248 2 \leq N\leq 248 2N248), each in the range 1 … 40 1 \ldots 40 140. In one move, Bessie cantake two adjacent numbers with equal values and replace them a singlenumber of value one greater (e.g., she might replace two adjacent 7swith an 8). The goal is to maximize the value of the largest numberpresent in the sequence at the end of the game. Please help Bessiescore as highly as possible!

输入格式

The first line of input contains N N N, and the next N N N lines give the sequence

of N N N numbers at the start of the game.

输出格式

Please output the largest integer Bessie can generate.

样例 #1

样例输入 #1

4
1
1
1
2

样例输出 #1

3

提示

In this example shown here, Bessie first merges the second and third 1s to

obtain the sequence 1 2 2, and then she merges the 2s into a 3. Note that it is

not optimal to join the first two 1s.

解题思路

dp[i][j]第i到j个数完全合并后的最大值,如果无法完全合并就为0。
dp[i][j]=max(dp[i][j],dp[i][k]+1) (dp[i][k]=dp[k+1][j]&dp[i][k]!=0)

代码实现

#include<iostream>
using namespace std;
int dp[250][250];
int main()
{int n;cin>>n;int ans=0;for(int i=1;i<=n;i++){cin>>dp[i][i];ans=max(ans,dp[i][i]);}for(int l=2;l<=n;l++){for(int i=1;i<=n-l+1;i++){int j=i+l-1;for(int k=i;k<j;k++){if(dp[i][k]!=0&&dp[i][k]==dp[k+1][j])dp[i][j]=max(dp[i][j],dp[i][k]+1);}ans=max(ans,dp[i][j]);}}cout<<ans;return 0;} 

[NOIP2007 提高组] 矩阵取数游戏

题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n × m n \times m n×m 的矩阵,矩阵中的每个元素 a i , j a_{i,j} ai,j 均为非负整数。游戏规则如下:

  1. 每次取数时须从每行各取走一个元素,共 n n n 个。经过 m m m 次后取完矩阵内所有元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 × 2 i \times 2^i ×2i,其中 i i i 表示第 i i i 次取数(从 1 1 1 开始编号);
  4. 游戏结束总得分为 m m m 次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

输入格式

输入文件包括 n + 1 n+1 n+1 行:

第一行为两个用空格隔开的整数 n n n m m m

2 ∼ n + 1 2\sim n+1 2n+1 行为 n × m n \times m n×m 矩阵,其中每行有 m m m 个用单个空格隔开的非负整数。

输出格式

输出文件仅包含 1 1 1 行,为一个整数,即输入矩阵取数后的最大得分。

样例 #1

样例输入 #1

2 3
1 2 3
3 4 2

样例输出 #1

82

提示

【数据范围】

对于 60 % 60\% 60% 的数据,满足 1 ≤ n , m ≤ 30 1\le n,m\le 30 1n,m30,答案不超过 1 0 16 10^{16} 1016
对于 100 % 100\% 100% 的数据,满足 1 ≤ n , m ≤ 80 1\le n,m\le 80 1n,m80 0 ≤ a i , j ≤ 1000 0\le a_{i,j}\le1000 0ai,j1000

【题目来源】

NOIP 2007 提高第三题。

解题思路

dp[i][j]:其中一行从i到j位置的最大得分。
dp[i][j]=max(dp[i][j-1]+a[j]*m,dp[i+1][j]+a[i]*m)

令m=pow(2,n-l+1),表示2^i 区间的长度越小,说明进行到此区间的次数比较靠后,也正因此m会越大。

注:本题要使用高精度实现
=> 高精度模板(加法,减法,乘法,除法,阶乘)<=

代码实现

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
#define MAX_N 80
int n,m;
class BigInt:public vector<int>
{public:BigInt(){push_back(0);}BigInt(int k){push_back(k);proccess_digit();}BigInt&operator+=(const BigInt&a){for(int i=0;i<a.size();i++){if(i>=size())push_back(0);at(i)+=a[i];}proccess_digit();return *this;}BigInt&operator*=(const int&a){for(int i=0;i<size();i++)at(i)*=a;proccess_digit();return *this;}BigInt operator*(const BigInt&a){BigInt c;for(int i=0;i<size();i++){for(int j=0;j<a.size();j++){if(i+j>=c.size())c.push_back(0);c.at(i+j)+=at(i)*a[j];}}c.proccess_digit();return c;}BigInt&operator*=(const BigInt&a){*this=(*this)*a;return *this;}BigInt operator/(int a){BigInt ret(*this);long long now=0;for(int i=size()-1;i>=0;i--){now=10*now+at(i);ret[i]=now/a;now%=a;}return ret;}BigInt&operator/=(int a){*this=(*this)/a;return *this;}bool operator<(const BigInt&a){if(size()>a.size())return false;else if(size()<a.size())return true;else{for(int i=size()-1;i>=0;i--)if(at(i)<a[i])return true;else if(at(i)>a[i])return false;}return false;}void proccess_digit(){for(int i=0;i<size();i++){if(at(i)<10)continue;if(i==size()-1)push_back(0);at(i+1)+=at(i)/10;at(i)%=10; }return ;}
};
ostream&operator<<(ostream&out,BigInt&a)
{int flag=1;for(int i=a.size()-1;i>=0;i--){if(flag&&!a[i])continue;out<<a[i];flag=0;}if(flag)out<<0;return out;
}
BigInt dp[MAX_N+5][MAX_N+5];
BigInt arr[MAX_N+5][MAX_N+5];
int main()
{cin>>n>>m;int x;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){cin>>x;arr[i][j]+=x;}BigInt mi=1;BigInt ans=0;for(int k=1;k<=n;k++){memset(dp,0,sizeof dp);for(int i=1;i<=m;i++)mi*=2;for(int i=1;i<=m;i++){dp[i][i]=arr[k][i]*mi;}		mi/=2;for(int l=2;l<=m;l++){for(int i=1;i<=m-l+1;i++){int j=i+l-1;BigInt temp1;temp1+=dp[i][j-1];temp1+=arr[k][j]*mi;BigInt temp2;temp2+=dp[i+1][j];temp2+=arr[k][i]*mi;if(temp1<temp2)dp[i][j]=temp2;else dp[i][j]=temp1;}mi/=2;}ans+=dp[1][m];}cout<<ans;return 0;} 

[CQOI2007] 涂色

题目描述

假设你有一条长度为 5 5 5 的木板,初始时没有涂过任何颜色。你希望把它的 5 5 5 个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为 5 5 5 的字符串表示这个目标: RGBGR \texttt{RGBGR} RGBGR

每次你可以把一段连续的木板涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木板涂成 RRRRR \texttt{RRRRR} RRRRR,第二次涂成 RGGGR \texttt{RGGGR} RGGGR,第三次涂成 RGBGR \texttt{RGBGR} RGBGR,达到目标。

用尽量少的涂色次数达到目标。

输入格式

输入仅一行,包含一个长度为 n n n 的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。

输出格式

仅一行,包含一个数,即最少的涂色次数。

样例 #1

样例输入 #1

AAAAA

样例输出 #1

1

样例 #2

样例输入 #2

RGBGR

样例输出 #2

3

提示

40 % 40\% 40% 的数据满足 1 ≤ n ≤ 10 1\le n\le 10 1n10

100 % 100\% 100% 的数据满足 1 ≤ n ≤ 50 1\le n\le 50 1n50

解题思路

dp[i][j]:从i到涂到j的最小涂色次数。
dp[i][j]=dp[i][j-1]+1 (a[i]==a[j])
dp[i][j]=min(dp[i][k]+dp[k+1][j]) (a[i]!=a[j])
解释:如果一段区间最后一个元素和第一个元素相等,可以直接滤去最后一个元素,因为此时直接从第一个涂到现在的最后一个只用一次,原先从第一个涂到最后一个也只用一次,所以等同于没有放。如果最后一个位置的颜色和第一个不相同,那么肯定存在两个区间涂色没有重合,所以遍历所有的一对区间找最小值。

代码实现

#include<iostream>
#include<string>
#include<cstring> 
using namespace std;
#define MAX_N 50
int dp[MAX_N+5][MAX_N+5];
int main()
{string s;cin>>s;int len=s.size();memset(dp,0x7f7f7f,sizeof dp);for(int i=1;i<=len;i++)dp[i][i]=1;for(int l=2;l<=len;l++){for(int i=1;i<=len-l+1;i++){int j=i+l-1;if(s[i-1]==s[j-1])dp[i][j]=dp[i][j-1];else for(int k=i;k<j;k++){dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);}}}cout<<dp[1][len];return 0;} 

[SCOI2003] 字符串折叠

题目描述

折叠的定义如下:

  1. 一个字符串可以看成它自身的折叠。记作 S = S

  2. X(S) X X XS连接在一起的串的折叠。记作 X(S) = SSSS…S

  3. 如果 A = A’, B = B’,则 AB = A’B’ 。例如:因为 3(A) = AAA, 2(B) = BB,所以 3(A)C2(B) = AAACBB,而 2(3(A)C)2(B) = AAACAAACBB

给一个字符串,求它的最短折叠。

例如 AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD

输入格式

仅一行,即字符串 S,长度保证不超过 100 100 100

输出格式

仅一行,即最短的折叠长度。

样例 #1

样例输入 #1

NEERCYESYESYESNEERCYESYESYES

样例输出 #1

14

提示

一个最短的折叠为:2(NEERC3(YES))

解题思路

dp[i][j]:从区间i到j的最短折叠长度
dp[i][j]=min(dp[i][k]+dp[k+1][j],dp[i][k]+2+m[len/loop]) if(区间[i,j]存在折叠,且循环节长度为loop)
dp[i][j]=min(dp[i][k]+dp[k+1][j]) if(区间不存在折叠)

理解:如果区间不存在可以折叠的情况,那么区间[i,j]的最小折叠长度就是某两个区间最小长度的和,取最小值。
如果存在折叠情况,并且找到了循环节长度为loop,那么此时就可以求得强制折叠的长度,此时就可以比较选择最小值。

代码实现

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
#define MAX_N 100
int dp[MAX_N+5][MAX_N+5];
int m[MAX_N+5];
string s;
bool check(int i,int j,int loop)
{for(int now=i;now<=j;now++){if(s[(now-i)%loop+i]!=s[now])return false;}return true;
}
int main()
{cin>>s;int n=s.size();memset(dp,0x7f7f7f,sizeof dp);for(int i=1;i<=n;i++)dp[i][i]=1;for(int i=1;i<=9;i++)m[i]=1;for(int i=10;i<=99;i++)m[i]=2;m[100]=3;for(int l=2;l<=n;l++){for(int i=1;i<=n-l+1;i++){int j=i+l-1;for(int k=i;k<j;k++){dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);}for(int k=i;k<j;k++){int loop=k-i+1;if(l%loop!=0)continue;if(check(i-1,j-1,loop))dp[i][j]=min(dp[i][j],dp[i][k]+2+m[l/loop]);}}}cout<<dp[1][n];return 0;
}

这篇关于Part 4.3 区间动态规划的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1071473

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

hdu4267区间统计

题意:给一些数,有两种操作,一种是在[a,b] 区间内,对(i - a)% k == 0 的加value,另一种操作是询问某个位置的值。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import

hdu4417区间统计

给你一个数列{An},然后有m次查询,每次查询一段区间 [l,r] <= h 的值的个数。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamRead

hdu3333区间统计

题目大意:求一个区间内不重复数字的和,例如1 1 1 3,区间[1,4]的和为4。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2