Description
Input
Output
Sample Input
10 5 1 2 3 6 7 9 11 22 44 50
Sample Output
9
这题是区间dp经典,看了别人的代码,自己写出来了。可以先设两个数组sum[i][j]和dp[i][j],sum[i][j]表示第i和第j个村庄之间建一个邮局并且这些村庄的花费都和这个邮局计算得到的最小花费,dp[i][j]表示前i个村庄中间j个邮局并且这i个村庄的花费计算都与这些邮局有关的最小花费。
那么前i个村庄中建j个邮局的最小花费可以由前k个村庄中建i-1个邮局的最小花费加上第k个邮局到第i个邮局建一个邮局的最小花费转移过来,即dp[i][j]=min(dp[i][j],dp[k][j-1]+sum[k+1][i]);
这里的初始条件是dp[i][1]=sum[1][i].
当邮局数为1时,我们把邮局建在中间就行了,当邮局有多个时,就有sum[i][j]=sum[i][j-1]+pos[j]-pos[(i+j)/2]。
#include<stdio.h> #include<string.h> #define maxn 350 #define inf 88888888 int min(int a,int b){ return a<b?a:b; } int pos[maxn],sum[maxn][maxn],dp[maxn][35]; int main() { int n,m,i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { memset(dp,inf,sizeof(dp)); memset(sum,0,sizeof(sum)); for(i=1;i<=n;i++){ scanf("%d",&pos[i]); } if(n==m){ printf("0\n");continue; } for(i=1;i<=n-1;i++){ for(j=i+1;j<=n;j++){ sum[i][j]=sum[i][j-1]+pos[j]-pos[(i+j)/2]; } } for(i=1;i<=n;i++){ dp[i][1]=sum[1][i]; } for(j=2;j<=m;j++){ for(i=j+1;i<=n;i++){ for(k=1;k<=i;k++){ dp[i][j]=min(dp[i][j],dp[k][j-1]+sum[k+1][i]); } } } printf("%d\n",dp[n][m]); } return 0; }
这题可以用四边形优化
#include<iostream> #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 int pos[350],dp[350][40],sum[350],s[350][350]; int getsum(int i,int j) { if(i==j)return 0; int mid=(i+j)/2; int num; num=(mid-i)*pos[mid]-(sum[mid]-sum[i-1])+sum[j]-sum[mid-1]-(j-mid)*pos[mid]; return num; } int main() { int n,m,i,j,num,k; while(scanf("%d%d",&n,&m)!=EOF) { sum[0]=0; memset(s,0,sizeof(s)); for(i=1;i<=n;i++){ scanf("%d",&pos[i]); sum[i]=sum[i-1]+pos[i]; s[i][1]=1; } dp[1][1]=0; for(i=2;i<=n;i++){ dp[i][1]=getsum(1,i); } for(j=2;j<=m;j++){ s[n+1][j]=n; for(i=n;i>j;i--){ dp[i][j]=inf; for(k=s[i][j-1];k<=s[i+1][j];k++){ //这里因为要得到k的范围,首先要得到s[i][j-1]和s[i+1][j]的值,所以要循环要从n到j+1 if(dp[i][j]>dp[k][j-1]+getsum(k+1,i)){ dp[i][j]=dp[k][j-1]+getsum(k+1,i); s[i][j]=k; } } } /*printf("--->%d %d\n",j,dp[n][j]);*/ } printf("%d\n",dp[n][m]); } return 0; }