山区建小学(区间型动态规划,递推)

描述
政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m。为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 )。请根据给定的m、n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。
输入第1行为m和n,其间用空格间隔
第2行为(m-1) 个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。
例如
10 3
2 4 6 5 2 4 3 1 3
表示在10个村庄建3所学校。第1个村庄与第2个村庄距离为2,第2个村庄与第3个村庄距离为4,第3个村庄与第4个村庄距离为6,...,第9个村庄到第10个村庄的距离为3。输出各村庄到最近学校的距离之和的最小值。样例输入
10 2
3 1 3 1 1 1 1 1 3
样例输出
18

/*
//感谢SilverNebula的https://blog.csdn.net/silvernebula/article/details/51379005
//感谢Always_ease的https://blog.csdn.net/Always_ease/article/details/80527234
思路汇总:
结论1:
    不管每个山村之间隔多远
    在第i山村到第j个山村中所有点,如果只建一个学校,取(i+j)/2这个山村建学校能使
    总距离最小,无论i+j是奇数还是偶数
    我的不严谨推理:如果把学校建两边是最差情况,所以尽量往中间建咯
    如果是1,2,3,4这种情况建在2和3其实总距离一样,可以自己证一下

结论2:
    已经有i个山村j-1个学校,现在建第j个学校,前j-1个山村是绝对不会被挖走而改变路线的
    让k=j-1,k表示前k个村庄不改变路线,现在让k一直自增来枚举各种情况(第j个学校到底改变了几个村庄)
    再找出各种k中最好的情况就好了
    也就是第j个学校的出现把局面分成了
    第1到k各山村和第k到i个山村,第i个山村只有一个学校,也就是那个新学校,所以很好求
    前1到k个山村,就是考虑k个村庄,j-1个学校,这些都是前面递推出来的,直接套用前面的
步骤:
1.计算任意两地之间距离,存入数组a
2.计算任意两地之间如果只有只有一个学校,那么两地之间所有村庄到这个学校
的距离和的最小值(两地中间建学校,距离总和最小)
3.为f数组赋上初值,即当1个学校匹配任意村庄的距离和
4.依次考虑加入新学校后有多少村庄为此改变路线,找出最好情况
*/
//我好弱啊,每题都要看答案才能学会做出来
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn=520;
ll a[maxn][maxn]={0},c[maxn][maxn],f[maxn][maxn];
//数组a:两个点之间距离;;;数组c:闭区间[i,j]内所有点到最近学校的距离和
//数组f:f[i][j]表示i个村庄j个学校所有村庄到最近学校的距离总和
int main()
{
    ll i,n,t,j,k,l,m,mid,s=INT_MAX;//s是一个很大非常大的值
    cin>>m>>n;//m为村庄,n为小学
    for(i=1;i<m;i++)    scanf("%lld",&a[i][i+1]);//依次输入第i个村庄到下一个村庄的距离
    for(i=1;i<=m;i++)//遍历每一种i,j配对
        for(j=i+1;j<=m;j++)
        {//数组a:两个点之间距离;
            a[i][j]=a[i][j-1]+a[j-1][j];//比如说a[2][5]=a[2][4]+a[4][5],
            //先考虑a[j-1][j]前面已经输入过,再考虑a[i][j]-a[j-1][j]=a[i][j-1],
            //而a[i][j-1]这个数据在a[i][j],循环到a[i][j]时a[i][j-1]已经计算完了,
            //所以等式成立;
            //其中a[2][3]和a[3][4]在前面输入时就已经给出了
            a[j][i]=a[i][j];//镜像复制刚刚只考虑i<j情况,现在给出另一半
            //比如a[2][4]=a[4][2]
        }
    for(i=1;i<=m;i++)//遍历每一种i,j配对
        for(j=i+1;j<=m;j++)
        {
            mid=(i+j)/2;//让mid锁定在序号为中间的村庄
            //@1,@2,@3,@4=>>>>@2  (1+4)/2=2
            //@1,@2,@3=>>>>@2       (1+3)/2=2
            c[i][j]=0;//先让闭区间[i,j]内所有点到最近学校的距离和为0
            //数组c:闭区间[i,j]内所有点到最近学校的距离和
            for(k=i;k<=j;k++)//枚举闭区间[i,j]的各个点为k
                c[i][j]+=a[k][mid];//c[i][j]+=[i,j]内各个点到mid点的距离和
        }
    for(i=1;i<=m;i++)
        f[i][1]=c[1][i];
        //赋初值,i个村庄只有一个学校时答案是确定的,就是这区间内所有点到中间点的距离和
    for(i=1;i<=m;i++)
        for(j=2;j<=n;j++)//一个学校的情况考虑过了,现在j可以从2开始算
        {
            f[i][j]=s;//先把每种情况的答案初始化为很大的值
            for(k=j-1;k<=i;k++)//枚举已有的学校管辖的范围//k确实最小值为j-1
                f[i][j]=min(f[i][j],f[k][j-1]+c[k+1][i]);//找出最小值
                    //在for循环中,f[i][j]经常改变,所以要让f[i][j]和k对应情况比较多次
        }//拿j和j-1时比较
/*
把j看作新学校,本来已经有i个村庄和j-1个学校,现在考虑有多少个村庄要投靠新学校i
毫无疑问,如果原来j-1个旧学校,那么能保证j-1位及之前村庄不会改变
*/
    cout<<f[m][n]<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/zyacmer/p/9903117.html

时间: 2024-10-06 10:43:00

山区建小学(区间型动态规划,递推)的相关文章

P4677 山区建小学|区间dp

P4677 山区建小学 题目描述 政府在某山区修建了一条道路,恰好穿越总共nn个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di 为了提高山区的文化素质,政府又决定从n个村中选择m个村建小学. 请根据给定的n.m以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值. 题解:https://www.luogu.org/blog/hsfzLZH1/solution-p4677 区间dp主要是下面这几段

ybt1197;p4677 山区建小学(博客里第一道蓝题)

ybt1197;p4677 山区建小学 [题目描述] 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0<i<m.为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设0<n≤m<500).请根据给定的m.n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值. [输入] 第1行为m和n,其间用空格间隔 第2行

NOI题库7624 山区建小学

7624:山区建小学 Description 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m.为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 ).请根据给定的m.n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值. Input 第1行为m

7624:山区建小学

7624:山区建小学 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m.为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 ).请根据给定的m.n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村

区间型动态规划的记忆化搜索实现与环形动态规划的循环数组实现

区间型动态规划的典型例题是石子归并,同时使用记忆化搜索实现区间动归是一种比较容易实现的方式,避免了循环数组实现的时候一些边界的判断 n堆石子排列成一条线,我们可以将相邻的两堆石子进行合并,合并之后需要消耗的代价为这两堆石子的质量之和,问最小的合并代价 状态转移方程很容易给出: f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[i][j]) 因为要计算区间和,考虑前缀和进行预处理 然后我们给出用记忆化搜索形式实现的代码,这里的记忆化搜索形式可以作为后续问题的一个模

山区建小学 (动态规划)

政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0<i<m.为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设0<n≤m<500).请根据给定的m.n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值. 输入 第1行为m和n,其间用空格间隔 第2行为m−1 个整数,依次表示从一端到另一端的相邻村庄的距离,

openjudge7624 山区建小学

描述 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m.为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 ).请根据给定的m.n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值. 输入第1行为m和n,其间用空格间隔第2行为(m-1) 个整数,

石子归并---区间型动态规划

题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1].问安排怎样的合并顺序,能够使得总合并代价达到最小. 输入描述 Input Description 第一行一个整数n(n<=100) 第二行n个整数w1,w2...wn  (wi <= 100) 输出描述 Output Description 一个整数表示最小合并代价 样例输入 Sample Input 4 4 1 1 4 样

openjudge 7624:山区建小学

描述 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m.为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 ).请根据给定的m.n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值. 输入第1行为m和n,其间用空格间隔第2行为(m-1) 个整数,