【noi 2.6_7624】山区建小学(DP)
题意:在m个村庄建n个小学,求所有村到最近小学的距离总的最小值。
解法:由于题目是求“离最近的学校”,而不是前一个学校,所以枚举学校的具体位置不方便,可转化成区间(学校居区间中间)的划分问题。
实现:dis[l][r]存村庄l和村庄r之间建1个小学的最小距离和,即到中间那个村庄的距离和。f[i][j]表示前i个村庄建了j个小学的最小距离和。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 5 const int N=510,M=510; 6 int a[N],s[N],f[N][M],dis[N][N]; 7 8 int mmin(int x,int y) {return x<y?x:y;} 9 int main() 10 { 11 int n,m; 12 scanf("%d%d",&n,&m); 13 s[1]=0; 14 for (int i=2;i<=n;i++) 15 { 16 scanf("%d",&a[i]); 17 s[i]=s[i-1]+a[i];//=1到i的距离 18 } 19 for (int l=1;l<=n;l++) 20 for (int r=l;r<=n;r++) 21 { 22 int mid=(l+r)>>1; 23 dis[l][r]=0; 24 for (int k=l;k<mid;k++) 25 dis[l][r]+=s[mid]-s[k]; 26 for (int k=mid+1;k<=r;k++) 27 dis[l][r]+=s[k]-s[mid]; 28 } 29 memset(f,63,sizeof(f)); 30 f[0][0]=0; 31 for (int i=1;i<=n;i++) 32 for (int j=1;j<=m;j++) 33 { 34 if (j>i) {f[i][j]=0;continue;} 35 for (int k=j-1;k<i;k++) 36 f[i][j]=mmin(f[i][j],f[k][j-1]+dis[k+1][i]); 37 } 38 printf("%d\n",f[n][m]); 39 return 0; 40 }