• 山区建小学(区间dp+前缀和+预处理)


    【题目描述】

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

    【题目链接】

        http://noi.openjudge.cn/ch0206/7624/

    【算法】

    1. 定义dp[i][j]为前i个村庄建j个小学,构建状态转移方程为dp[i][j] = min(dp[i][j], dp[k][j] + cost[i+1][j])  其中cost[i][j]表示第i个村庄到第j个村庄建一个小学的最短距离和
    2. 预处理cost数组,众所周知,满足最短距离和的小学应该建在中位数的村庄处,同时也满足递推关系:cost[i][j] = cost[i][j-1] + dist[j] - dist[i+j>>1]
    3. 前缀和就是村庄所处位置

    【代码】

      

    #include <iostream>
    #include <stdlib.h>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int m,n,i,j,k;
    int dist[510],cost[510][510],dp[510][510];
    int main()
    {
        cin>>m>>n;
        dist[1]=1;
        for(i=2;i<=m;i++)
            cin>>dist[i],dist[i]+=dist[i-1];
        for(i=1;i<=m;i++)
            for(j=i+1;j<=m;j++)
                cost[i][j]=cost[i][j-1]+dist[j]-dist[i+j>>1];
        memset(dp,0x7f,sizeof(dp));
        for(i=1;i<=m;i++) dp[i][1]=cost[1][i];
        for(i=2;i<=m;i++)
            for(j=2;j<=min(i,n);j++)
                for(k=j-1;k<i;k++)
                    dp[i][j]=min(dp[i][j],dp[k][j-1]+cost[k+1][i]);
        cout<<dp[m][n];
        return 0;
    }
  • 相关阅读:
    python实现二分查找算法例子代码
    Python实现计算圆周率π的值到任意位的方法示例
    什么是TWS耳机
    [置顶] 单例模式lua实现
    推荐五星级C语言学习网站
    poj2689 Prime Distance 有难度 埃拉托斯尼斯筛法的运用
    局域网
    pager-taglib分页处理的使用
    创建ListView的基本步骤
    求最大连续子数列和(只扫描一次数列)
  • 原文地址:https://www.cnblogs.com/Willendless/p/9327841.html
Copyright © 2020-2023  润新知