题目大意:

给定n个村庄的坐标,两个村庄之间的距离是其坐标之差的绝对值

最多能选m个村庄设立邮局,求设立邮局的地点使得各村庄与邮局距离总和最小

一,

所有的村庄看做在一条直线上

考虑三个因素:i 当前位于第几个村庄,j 已设立邮局的个数,s 村庄与邮局的距离总和

即dp数组为 dp[ i ][ j ] = s  , 区间DP,枚举中间点村庄 k

则dp[ i ][ j ]=max{ dp[ k ][ j-1 ] + s( k+1,i ) | 0<k<i}

(1~i村庄设j个邮局) 可由 (1~k村庄设j-1个邮局)+(k+1~i村庄设1个邮局) 得到

二,

再来考虑如何处理s( k,i ),即第 k+1 到 i 村庄之间设立一个邮局的最短距离

即考虑一个区间内选取哪个点可使 其他点到该点的差值的绝对值总和 是最小的

两个点以上的情况 首先可以排除首端和尾端的两个点

奇数个点的情况:

设a<b<c<d<e

1.选取b时

a   b   c   d   e

---

---

-------

----------

2.选取c时

a   b   c   d   e

------

---

---

------

可看出选取中间点更优

偶数个点的情况:

设a<b<c<d<e<f

1.选取c时

a   b   c   d   e   f

------

---

---

------

----------

2.选取d时

a   b   c   d   e   f

---------

------

---

---

------

可看出选取居中的两个点得到的结果是一样的

那么举个例子: s( a,d )=s( a,c )+d到邮局的距离,邮局最佳设立位置为(a+d)/2

就可得到 s( a,d )=s( a,c )+a[ d ]-a[ (a+d)/2 ]

则设数组s[][]保存 两点间设立一个邮局时 区间内村庄与邮局间距离总和的最小值

且 s[ i ][ j ]=s[ i ][ j-1 ] + a[ j ] - a[ (i+j)/2 ]

三,

邮局地点的记录(类似最长上升子序列的路径记录)

利用dp[i][j]的更新过程,枚举中间点k时,若其能更新当前的dp[i][j],

说明 1~i 被分为两个区间 1~k 和 k+1~i,则区间 k+1~i 的邮局设立点为 (i+k+1)/2

那么记录此时前驱为 k,即 pre[i][j]=k,即记录了上一个区间的末尾

则当dp[][]更新结束后,dp[n][m]是1~n村庄设立m个邮局的距离总和最小值

pre[n][m]中记录的是倒数第二个区间的末尾k1,邮局设立点为(n+k1+1)/2

则pre[k1][m-1]中则记录着倒数第三个区间的末尾k2,邮局设立点为(k1+k2+1)/2

则pre[k2][m-2]中则记录着倒数第四个区间的末尾k3 ,......

这样逆推下去 就可以当推到0时 代表已经过了第一个区间

  1. #include <bits/stdc++.h>
  2. #define INF 0x3f3f3f3f
  3. using namespace std;
  4.  
  5. int n,m,a[];
  6. int s[][]; // s[i][j] 在i到j之间设一个邮局的最小距离
  7. int dp[][]; // dp[i][j] 前i个村落设j个邮局的最小花费
  8. int pre[][],ans[];
  9.  
  10. int main()
  11. {
  12. while(~scanf("%d%d",&n,&m)) {
  13.  
  14. memset(s,,sizeof(s));
  15. memset(dp,INF,sizeof(dp));
  16. memset(pre,,sizeof(pre));
  17.  
  18. for(int i=;i<=n;i++) scanf("%d",&a[i]);
  19. for(int i=;i<=n;i++) {
  20. for(int j=i+;j<=n;j++)
  21. s[i][j]=s[i][j-]+a[j]-a[(i+j)/];
  22. dp[i][]=s[][i]; // 顺带更新一下1~i设1个邮局的dp[][]
  23. }
  24.  
  25. for(int i=;i<=n;i++) // 枚举末尾
  26. for(int j=;j<=i && j<=m;j++) // 枚举邮局个数
  27. for(int k=j-;k<i;k++) // 枚举 1~i 的中间点
  28. if(dp[k][j-]+s[k+][i]<dp[i][j])
  29. dp[i][j]=dp[k][j-]+s[k+][i], pre[i][j]=k;
  30.  
  31. int x=n,y=m,ind=;
  32. while(x>&&y>) { /// 逆推并将邮局设立位置逆序存入ans[]
  33. ans[ind++]=a[(x+pre[x][y]+)/];
  34. x=pre[x][y--];
  35. }
  36.  
  37. printf("%d\n",dp[n][m]);
  38. while(ind>) { // 从最后一个输出 才是正序
  39. printf("%d ",ans[--ind]);
  40. } printf("\n");
  41. }
  42.  
  43. return ;
  44. }

Post Office IOI 2000 /// 区间DP oj24077的更多相关文章

  1. [IOI 2000]POJ 1160 Post Office

    Post Office Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22278 Accepted: 12034 Descrip ...

  2. IOI 98 (POJ 1179)Polygon(区间DP)

    很容易想到枚举第一步切掉的边,然后再计算能够产生的最大值. 联想到区间DP,令dp[i][l][r]为第一步切掉第i条边后从第i个顶点起区间[l,r]能够生成的最大值是多少. 但是状态不好转移,因为操 ...

  3. UVALive 4987---Evacuation Plan(区间DP)

    题目链接 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...

  4. 2016 ACM/ICPC Asia Regional Shenyang Online 1009/HDU 5900 区间dp

    QSC and Master Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  5. poj 3186 Treats for the Cows(区间dp)

    Description FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money for gi ...

  6. [poj3280]Cheapest Palindrome_区间dp

    Cheapest Palindrome poj-3280 题目大意:给出一个字符串,以及每种字符的加入代价和删除代价,求将这个字符串通过删减元素变成回文字符串的最小代价. 注释:每种字符都是小写英文字 ...

  7. hdu 4283 区间dp

    You Are the One Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  8. POJ1179Polygon(区间dp)

    啊~~ 被dp摁在地上摩擦的人 今天做了一道区间dp的题(POJ1179Polygon) 题目: Polygon Time Limit: 1000MS   Memory Limit: 10000K T ...

  9. 区间dp(入门题)

    区间dp:顾名思义就是在区间上进行动态规划,通过合并小区间求解一段区间上的最优解. 常见模板: for(int len=1;len<n;len++){//区间长度 for(int be=1;be ...

随机推荐

  1. 为什么要使用动态链接库(DLL)

    为什么要使用动态链接库(DLL)   第一章 为什么要使用动态链接库(DLL) top 提起DLL您一定不会陌生,在Windows中有着大量的以DLL为后缀的文件,它们是保证Windows正常运行和维 ...

  2. js实现canvas保存图片为png格式并下载到本地

    canvas 保存图片 下载到本地 function base64Img2Blob(code){ var parts = code.split(';base64,'); var contentType ...

  3. javafx教程大全

    链接: https://www.yiibai.com/javafx

  4. NOIp2018集训test-9-17(pm)

    T1记忆(memory) 我大概是只记忆只有七秒的金鱼吧.看了下以前的代码发现真的很简单,但是考场上只打了个暴力,虽然骗了88pt.就是枚举选的是哪个串,然后vis[i]表示选了i这些位能不能猜出它, ...

  5. How to SSH Into Your iPhone

    First, I will explain what SSH is and why we do it. SSH (Secure Shell) allows you to exchange data b ...

  6. Oracle 生成sys_guid

    select sys_guid() from dual;select sys_guid() from dual connect by rownum<100

  7. 顺时针打印矩阵元素(python实现)

    我觉得我的算法比较简单易懂,比网上的那些简单些.至于时间复杂度就没有比较了. 算法思想:从最外层向内层遍历矩阵 # my algorithmimport math def print_matrix(m ...

  8. Day 9 :初识函数

    Python函数:1.函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 2.函数能提高应用的模块性,和代码的重复利用率. Python提供了许多内建函数,比如print().但你也可 ...

  9. js 关闭页面(Scripts may close only the windows that were opened by it.)

    传送http://blog.csdn.net/kuangfengbuyi/article/details/52052301 js关闭当前页面,当该页面不是其他页面打开的,而是直接输入url, 直接用w ...

  10. Python高级核心技术97讲✍✍✍

    Python高级核心技术97讲  整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大家看的时候可以 ...