Description
Input
Output
Sample Input
3 2 5 1
Sample Output
11
第一道区间dp,这题设一个数组dp[i][j]表示从i取到j的最小得分。
状态转移方程:用len表示所选数字的个数,dp[i][i+len-1]=min(dp[i][i+len-1],dp[i][k]+dp[k+1][i+len-1]+sum[i+len-1]-sum[i-1]);这里注意所有的dp[i][i]为0,因为只有一个数的时候不用合并,所以是0。因为题目允许第一次开始取的时候相邻数字能搞交换,所以外面加个循环,同时每次的sum[]都要重新初始化。另外,这题用四边形优化会大大加快速度。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; #define inf 99999999 #define ll long long int sum[200],a[200]; int dp[200][200]; int main() { int n,m,i,j,c,len,k,t; int minx; while(scanf("%d",&n)!=EOF) { sum[0]=0; for(i=1;i<=n;i++){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; dp[i][i]=0; } minx=inf; for(t=1;t<=n-1;t++){ sum[t]=sum[t]-a[t]+a[t+1]; for(len=2;len<=n;len++){ for(i=1;i<=n-len+1;i++){ dp[i][i+len-1 ]=inf; for(k=i;k<=i+len-2;k++){ dp[i][i+len-1]=min(dp[i][i+len-1],dp[i][k]+dp[k+1][i+len-1]+sum[i+len-1]-sum[i-1]); } } } sum[t]=sum[t]+a[t]-a[t+1]; minx=min(minx,dp[1][n]); } printf("%d\n",minx); } return 0; }
四边形优化:#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; #define inf 99999999 #define ll long long int sum[200],a[200],s[200][200];/*s[i][j]函数表示区间[i,j]从k点分开是最优的*/ int dp[200][200]; int main() { int n,m,i,j,c,len,k,t; int minx; while(scanf("%d",&n)!=EOF) { sum[0]=0; for(i=1;i<=n;i++){ scanf("%d",&a[i]); s[i][i]=i; sum[i]=sum[i-1]+a[i]; dp[i][i]=0; } minx=inf; for(t=1;t<=n-1;t++){ sum[t]=sum[t]-a[t]+a[t+1]; for(len=2;len<=n;len++){ for(i=1;i<=n-len+1;i++){ j=i+len-1; dp[i][j]=inf; for(k=s[i][j-1];k<=s[i+1][j];k++){ if(dp[i][j]>dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]){ dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]; s[i][j]=k; } } } } sum[t]=sum[t]+a[t]-a[t+1]; minx=min(minx,dp[1][n]); } printf("%d\n",minx); } return 0; }