1197:山区建小学
该题的难点在于存在两个“子动态规划”并且需要用一个中间数组将两个“子动态规划”联系起来。
解题思路:
- 计算任意两个村子之间的距离,用动态规范显然降低了不少复杂度。(都可以单独出一个题目了~~(╯﹏╰)~~)
- 在任意两个村子之间建一所小学,并计算两个村子之间的所有村子到该小学的最短距离,求解所有情况。
- 计算在第1~i个村子中间建j所小学的最短距离,f[i][j]=1~k个村子建j-1所小学的最短距离与k+1~i个村子建一所小学(正好契合了中间数组)的最短距离之和,使用动态规划再合适不过。(又可以单独出一个题目了~~(╯﹏╰)~~)
1 #include<iostream> 2 using namespace std; 3 4 const int N=505,MAX_DIS=0x7fffffff; 5 int a[N][N],b[N][N],f[N][N]; 6 int main(){ 7 int m,n; 8 cin>>m>>n; 9 for(int i=1;i<m;i++){ 10 cin>>a[i][i+1]; 11 a[i+1][i]=a[i][i+1]; 12 } 13 //计算任意两个村子之间的距离 14 for(int i=1;i<m;i++){ 15 for(int j=i+2;j<=m;j++){ 16 a[i][j]=a[j][i]=a[i][j-1]+a[j-1][j]; 17 } 18 } 19 //在任意两个村子之间建一所学校,计算两村子之间的所有村子到该学校的最短距离 20 for(int i=1;i<m;i++){ 21 for(int j=i+1;j<=m;j++){ 22 int pos=(i+j)/2;//两村子中间建学校距离最短? 23 for(int k=i;k<=j;k++){ 24 b[i][j]+=a[k][pos]; 25 } 26 } 27 } 28 //f[i][j]表示在前i个村子(1~i)里建j所小学的最短距离 29 //初始化 30 for(int i=1;i<=m;i++){ 31 f[i][1]=b[1][i]; 32 } 33 for(int i=3;i<=m;i++){ 34 for(int j=2;j<=n;j++){ 35 f[i][j]=MAX_DIS; 36 for(int k=1;k<i;k++) 37 f[i][j]=min(f[i][j],f[k][j-1]+b[k+1][i]); 38 } 39 } 40 cout<<f[m][n]; 41 return 0; 42 }
做了有好几个动态规划了(当然这题是披着递推的动态规划)
颇有几分心得:
如果你要看懂别人的动态规划题解,那么你必须知道其中二维数组的含义,比如a[i][j],你需要知道i、j和a[i][j]分别表示什么。
如果你要会写动态规划,那就努力去找其中的递推关系,或者说是大输入与小输入之间的联系,然后再用(一般)二维数组表达它们。
但难点往往在于:
- 有的递推关系(联系)很难找出
- 即使得到了一点递推关系的头绪,却又没有用二维数组表达它们的能力(像这题,需要使用多个二维数组表达多种联系)