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]分别表示什么。

如果你要会写动态规划,那就努力去找其中的递推关系,或者说是大输入与小输入之间的联系,然后再用(一般)二维数组表达它们。

但难点往往在于:

  • 有的递推关系(联系)很难找出
  • 即使得到了一点递推关系的头绪,却又没有用二维数组表达它们的能力(像这题,需要使用多个二维数组表达多种联系)
posted @ 2021-08-03 21:43  Rekord  阅读(1004)  评论(0编辑  收藏  举报