• YBT 山区建小学


    题目描述

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

    输入格式

       第1行为n和m,其间用空格间隔。

      第2行为n-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

    题解

      我们设$s[i][j]$为村庄$i$到村庄$j$间修小学的最短距离。

      贪心一下即可知,当我们把小学放到村庄$left lfloor frac{i + j}{2} ight floor$时,距离最短。

      我们设$dp[i][j]$为村庄$1$到村庄$i$间修$j$所小学的最短距离,容易得到$dp[i][j] = underset{1 leqslant k < i}{min} left { dp[k][j - 1] + s[k + 1][i] ight }$

    #include <iostream>
    #include <cstdio>
    
    #define MAX_N (500 + 5)
    #define MAX_M (500 + 5) 
    
    using namespace std;
    
    int n, m;
    int a[MAX_N][MAX_N];
    int s[MAX_N][MAX_N];
    int dp[MAX_N][MAX_M];
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for(register int i = 1; i < n; ++i)
        {
            scanf("%d", &a[i][i + 1]);
            for(register int j = i - 1; j; --j)
            {
                a[j][i + 1] = a[j][j + 1] + a[j + 1][i + 1];
            }
        }
        int mid;
        for(register int i = 1; i < n; ++i)
        {
            for(register int j = i + 1; j <= n; ++j)
            {
                mid = i + j >> 1;
                for(register int k = 0; i + k <= mid; ++k)
                {
                    s[i][j] += a[i + k][j - k];
                }
            }    
        }
        for(register int i = 1; i <= n; ++i)
        {
            dp[i][1] = s[1][i];
            for(register int j = 2; j <= i && j <= m; ++j)
            {
                dp[i][j] = 2147483647;
                for(register int k = 1; k < i; ++k)
                {
                    dp[i][j] = min(dp[i][j], dp[k][j - 1] + s[k + 1][i]);
                }
            }
        }
        printf("%d", dp[n][m]);
        return 0;
    }
    参考程序
  • 相关阅读:
    20180604_Myeclipse下配置SVN报错问题 svn
    20180603_升级Win10后,远程连接桌面连接,出现身份验证错误!
    20180603_navicat 连接sqlserver提示要安装 sql server native client
    VB.net程序实现分页
    多线程Demo
    多线程Demo VB.net
    SQLServer数据库子结构
    SQLServer数据库常用命令
    传播路径图调查2013年初
    拾遗
  • 原文地址:https://www.cnblogs.com/kcn999/p/10991345.html
Copyright © 2020-2023  润新知