题目大意:
给你n个数字v(1),v(2),...,v(n-1),v(n),每次你可以取出最左端的数字或者取出最右端的数字,一共取n次取完。假设你第i次取的数字是x,你可以获得i*x的价值。你需要规划取数顺序,使获得的总价值之和最大。
Input
第一行一个数字n(1<=n<=2000)。
下面n行每行一个数字v(i)。(1<=v(i)<=1000)Output
输出一个数字,表示最大总价值和。
Sample Input
5 1 3 1 5 2
Sample Output
43
题解:
一道区间dp的简单题,顺便重新看了一下以前我自己写的区间dp的博客,区间dp入门。
状态dp[i][j]表示从i到j的最大价值总和。
状态转移方程dp[i][j]=max(dp[i+1][j]+a[i]*(n+i-j),dp[i][j-1]+a[j]*(n+i-j)).
这里n+i-j就表示第几次取,因为j-(i+1)+1就表示从i+1到j区间的数的个数,即还有这么j-i个数没取,那么取a[i]就是第n-(j-i)次,i到j-1区间也一样。
代码实现:
#pragma GCC optimize(2) #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <cstdio> #include <cstdlib> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #define PI atan(1.0) * 4 #define E 2.718281828 #define rp(i, s, t) for (register int i = (s); i <= (t); i++) #define RP(i, t, s) for (register int i = (t); i >= (s); i--) #define ll long long #define ull unsigned long long #define mst(a, b) memset(a, b, sizeof(a)) #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define pii pair<int, int> #define mp make_pair #define pb push_back #define debug printf("ac\n"); using namespace std; inline int read() { int a = 0, b = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') b = -1; c = getchar(); } while (c >= '0' && c <= '9') { a = (a << 3) + (a << 1) + c - '0'; c = getchar(); } return a * b; } const int INF = 0x3f3f3f3f; const int N = 2e3 + 7; int dp[N][N], a[N]; int n; int main() { mst(dp,0); n = read(); rp(i, 1, n) a[i] = read(); for (int len = 1; len <= n; len++){ //枚举区间长度 for (int i = 1; i < n; ++i){//枚举区间的起点 int j = i + len - 1; //根据起点和长度得出终点 if (j>n)break; //符合条件的终点 dp[i][j]=max(dp[i+1][j]+a[i]*(n+i-j),dp[i][j-1]+a[j]*(n+i-j)); } } printf("%d\n", dp[1][n]); return 0; }
还有一种记忆化搜索的实现,思路更清晰,而且不用再算第几次取,只需要在搜索的时候记录就行。
状态和递推的状态是一样的。
代码实现:
#pragma GCC optimize(2) #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<cstdlib> #include<vector> #include<map> #include<set> #include<stack> #include<queue> #define PI atan(1.0)*4 #define E 2.718281828 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define mp make_pair #define pb push_back #define debug printf("ac\n"); using namespace std; inline int read() { int a=0,b=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') b=-1; c=getchar(); } while(c>='0'&&c<='9') { a=(a<<3)+(a<<1)+c-'0'; c=getchar(); } return a*b; } const int INF = 0x3f3f3f3f; const int N=2e3+7; int dp[N][N],a[N]; int n; int dfs(int l,int r,int times){ if(dp[l][r]>=0) return dp[l][r]; if(l>r||l<=0||r>=n+1) return 0; return dp[l][r]=max(dfs(l,r-1,times+1)+a[r]*times,dfs(l+1,r,times+1)+a[l]*times); } int main(){ n=read(); rp(i,1,n) a[i]=read(); mst(dp,-1); dfs(1,n,1); printf("%d\n",dp[1][n]); return 0; }
dp训练计划——poj3186区间dp简单题(递推+记忆化搜索)
猜你喜欢
转载自blog.csdn.net/qq_43472263/article/details/104687357
今日推荐
周排行