POJ 3186Treats for the Cows(区间DP)
题目链接:http://poj.org/problem?id=3186
题目大意:给出的一系列的数字,可以看成一个双向队列,每次只能从队首或者队尾出队,第n个出队就拿这个数乘以n,最后将和加起来,求最大和。
解题思路:有两种写法:
①这是我一开始想的,从外推到内,设立数组dp[i][j]表示剩下i~j时的最优解,则有状态转移方程:
dp[i][j]=dp[i][j]=max(dp[i-1][j]+a[i-1]*(n-(j-i+1)),dp[i][j+1]+a[j+1]*(n-(j+1-i)))
最后推到dp[i][i]就只剩下一个物品,再计算一次找最大值即可。
②网上看的,区间DP,由内推到外,有状态转移方程:dp[i][j]=max(dp[i+1][j]+a[i]*(n-j+i),dp[i][j-1]+a[j]*(n-j+i))
代码①:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long LL; 5 const int N=2e3+5; 6 const int inf=1<<30; 7 int a[N]; 8 int dp[N][N];//还剩下i~j件物品时的最优解 9 10 int main(){ 11 int n; 12 while(~scanf("%d",&n)){ 13 for(int i=1;i<=n;i++) 14 scanf("%d",&a[i]); 15 16 dp[0][5]=dp[1][6]=0; 17 for(int i=1;i<=n;i++){ 18 for(int j=n;j>=i-1;j--){ 19 dp[i][j]=max(dp[i-1][j]+a[i-1]*(n-(j-i+1)),dp[i][j+1]+a[j+1]*(n-(j+1-i))); 20 } 21 } 22 int ans=0; 23 for(int i=1;i<=n;i++){ 24 ans=max(dp[i][i]+n*a[i],ans); 25 } 26 printf("%d\n",ans); 27 } 28 return 0; 29 }
代码②:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=2e3+5; 6 const int inf=1<<30; 7 int a[N]; 8 int dp[N][N]; 9 10 int main(){ 11 int n; 12 while(~scanf("%d",&n)){ 13 memset(dp,0,sizeof(dp)); 14 for(int i=1;i<=n;i++) 15 scanf("%d",&a[i]); 16 17 for(int i=n;i>=1;i--){ 18 for(int j=i;j<=n;j++){ 19 dp[i][j]=max(dp[i+1][j]+a[i]*(n-j+i),dp[i][j-1]+a[j]*(n-j+i)); 20 } 21 } 22 printf("%d\n",dp[1][n]); 23 } 24 return 0; 25 }