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 }

 

posted @ 2017-09-10 16:19  Yeader  阅读(136)  评论(0编辑  收藏  举报