POJ 1160 经典区间dp

链接http://poj.org/problem?id=1160

很好的一个题,涉及到了以前老师说过的一个题目,可惜没往那上面想。

题意,给出N个城镇的地址,他们在一条直线上,现在要选择P个城镇建立邮局,使得每个城镇到离他最近的邮局距离的总和尽量小。

首先提一个这个问题的简化版本,如果P=1得话,这个距离是多少呢? 这个问题的解就是将这个唯一的邮局建在(l+r)/2的位置,答案就是最优解,

这个类似于中位数的概念,我们有一个数学归纳法简单的证明

数轴上有n个点,求到这n个点距离最小的一个点   问题描述:如题分析:这个题目不能简单地将所有点的平均数作为答案,这样是不对的,有反例。例如:x1=1, x2=3, x3=4, x4=100, 那么他们的平均数为x=27, 所有点到x的距离为146, 但当我们取x=10时,得打距离的值为116,比146更小。下面我们来用归纳法的思想来分析:如果n=1,那么就取这个点如果n=2,那么取x1和x2之间的任何一个点都是答案如果n=3,那么取中间的那个点,就是答案如果n=4,那么取中间的两个点所构成的闭区间就是答案... 如果n是奇数,那么就是第(n+1)/2这个点如果n是偶数,那么就是n/2这个点和(n/2)+1这两个点所构成的闭区间假设所有点都按序排列。
  同理也可以推广到二维平面选点,只要找两次x和y的中位数就是最佳的地址。

对于此题不难想到dp[i][j]表示前i个城镇建立j个邮局的最小花费距离,因为不是每个地方都有邮局所以用dp[i][j]表示i-j之间的话不太方便,起点总是1所以可以免去一维。

则 dp[i][j]=MIN{dp[i][j],dp[k][j-1]+dis[k+1][i]| ,1<=k<=i} 其中dis[a][b]表示a-b之间建立一个邮局的最小花费距离,由上面的方法可以引出递推式:dis[i][j]=dis[i][j-1]+x[j]-x[(i+j)/2]

一开始我卡住,因为想不通递推式,我想这个分割点k如果k后面的邮局选址会影响到前面某个点使得价值更低这样岂不是会计算错误吗,后来想了想发现,这样会使结果变大,但是总会循环到那个最优的k使得恰好互不影响。因为离某个城镇的邮局最近的地方只有两种情况,左边或者右边,如果到k时出现交叉即

i_______k______j,从k分割时,(k,j]之间建立的那个邮局使得[i,k]的某个点会有更小的距离。一直向右循环总会到达使得两边互不影响的点,此时计算得到最优解。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define inf 0x3f3f3f3f
 4 int dp[305][35];
 5 int x[305],one[305][305]={0};
 6 int main()
 7 {
 8     int N,M,i,j,k;
 9    // freopen("in.txt","r",stdin);
10     while(cin>>N>>M){
11         scanf("%d",&x[1]);
12         for(i=2;i<=N;++i)
13              scanf("%d",&x[i]);
14         memset(dp,inf,sizeof(dp));
15         for(i=1;i<=N;++i)
16             for(j=i;j<=N;++j)
17         if(i==j) one[i][i]=0;
18         else
19             one[i][j]=one[i][j-1]+x[j]-x[(i+j)/2];
20         for(i=1;i<=N;++i) dp[i][1]=one[1][i];
21         for(i=2;i<=N;++i)
22         {
23             int up=min(M,i);
24             for(j=2;j<=up;++j)
25             {
26                 for(k=1;k<=i;++k)
27                 {
28                    int s=dp[k][j-1]+one[k+1][i];
29                    if(dp[i][j]>s) dp[i][j]=s;
30                 }
31             }
32         }
33         printf("%d\n",dp[N][M]);
34     }
35     return 0;
36 }
时间: 2024-08-14 10:09:57

POJ 1160 经典区间dp的相关文章

POJ 1160 (区间DP+四边形优化)

这个转移方程不好想,尤其是一段值的解是中间,不明觉厉.dp[i][j] 用i个邮局,覆盖前j个村庄的最小值. 还有就是区间dp的平行四边形优化,这个题的转移方程并不是"区间DP",所以枚举状态要逆着(很花时间),且用一个邮局覆盖都是从0断开了相当于没有断开. 类比于石子归并,矩阵链乘等标准区间DP,其所需状态之前就已经获得,不用倒推 #include <cstdio> #include <cstring> #include <iostream> us

POJ 2955-Brackets(区间DP)

Brackets Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3340   Accepted: 1716 Description We give the following inductive definition of a "regular brackets" sequence: the empty sequence is a regular brackets sequence, if s is a reg

POJ 1179 Polygon 区间DP

链接:http://poj.org/problem?id=1179 题意:给出一个多边形,多边形的每个顶点是一个数字,每条边是一个运算符号"+"或者"x".要求的过程如下,手下移除一条边,即这条边不做运算.之后每次移除一条边,将其两边的数字进行对应边的运算,用得到的数字来替代原来的两个点.要求所有边都移除以后得到的最大的答案. 思路:典型的区间DP,在过程中每次操作的处理方式为dp_max[i][j]=dp[i][k]*dp[k+1][j],dp_max[i][j]

uva348 最优矩阵链乘 经典区间dp

// uva348 最优矩阵链乘 // 典型的区间dp // dp[i][j] 表示矩阵i到j链乘所得到的最小花费 // dp[i][j] = min(dp[i][k]+dp[k+1][j]+a[i].pl*a[k].pr*a[j].pr); // 在区间i到j上找一个k使得dp[i][k]+dp[k+1][j]这两部分的和在加上最后的 // a[i].pl*a[k].pr*p[i].pr的最小值; // 能有这样的状态关键是; P =A[1] * A[2] * .... * A[K] // 和

ZOJ3469 Food Delivery (经典区间dp)

本题和某一年的oi题非常相似,都是经典套路 我们知道我们在送完食物后既可以向前送也可以回头送,这就体现了区间dp的思想 为什么我们这次的区间dp不用枚举第三维k来枚举从哪里送过来呢? 因为送货员不是傻子,他如果送到你这了,那么在你们两之间的可以都顺路送了,所以我们只需要枚举两个位置就行 这题的输入不一定递增,所以建议输入完后排序 #include<iostream> #include<cstdio> #include<cstring> #include<algor

POJ 2955 Brackets (区间DP)

题意:给定一个序列,问你最多有多少个合法的括号. 析:区间DP,dp[i][j] 表示在 第 i 到 第 j 区间内最多有多少个合法的括号. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <ios

poj 1947 经典树形dp

经典树形dp:问在一棵树上最少删除多少条边可以分离出一个节点数为p的子树. 定义状态: dp[i][j]表示从i为根的子树上分离出一个节点数为j的子树的代价(最少需要删除的边数). 考虑i节点的每个儿子ii,ii可以选或者不选(切断),然后就转化成了背包问题. dp[u][j] = min( dp[u][j], dp[u][j - k] + dp[v][k] ); 1 #include <iostream> 2 #include <cstring> 3 #include <c

POJ 1159 Palindrome(区间DP/最长公共子序列+滚动数组)

Palindrome Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 56150   Accepted: 19398 Description A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a

poj 1390 Blocks (经典区间dp 方块消除)

Blocks Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4250   Accepted: 1704 Description Some of you may have played a game called 'Blocks'. There are n blocks in a row, each box has a color. Here is an example: Gold, Silver, Silver, Sil