首页 > 代码库 > poj1160 Post Office 四边形不等式

poj1160 Post Office 四边形不等式

在一条直线上有n个村庄,选出m个村庄,在其中每个村庄建立一个邮局,要求每个村庄到最近邮局的距离和最小。


f[i][j]:在前i个村庄中建立j个邮局的最小耗费
dis[i][j]:在第i个村庄到第j个村庄中建立1个邮局的最小耗费
那么就有转移方程:f[i][j] = min(f[i][j],f[k][j-1]+dis[k+1][i]) DP的边界状态即为f[i][1] = dis[1][i]; 所要求的结果即为f[n][m];

然后就说说求dis数组的优化问题,可以假定有6个村庄,村庄的坐标已知分别为p1,p2,p3,p4,p5,p6;那么,如果要求dis[1][4]的话邮局需要建立在2或者3处,
放在2处的消耗为p4-p2+p3-p2+p2-p1=p4-p2+p3-p1
放在3处的结果为p4-p3+p3-p2+p3-p1=p4+p3-p2-p1,
可见,将邮局建在2处或3处是一样的。现在接着求sum[1][5],现在处于中点的村庄是3,那么1-4到3的距离和刚才已经求出了,即为dis[1][4],所以只需再加上5到3的距离即可。
同样,求dis[1][6]的时候也可以用dis[1][5]加上6到中点的距离。
所以有递推关系:dis[i][j] = dis[i][j-1] + p[j] -p[(i+j)/2]

用四边形不等式优化了一下

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 1000
#define INF 100000000
using namespace std;
int n,m,i,j,k,p[N],dis[N][N],f[N][N],s[N][N];
void Init()  //初始化 
{
    for (i=1; i<=n; i++)
        for (j=1; j<=n; j++)
            f[i][j]=INF;
    for (i=1; i<=n; i++)    
        f[i][1]=dis[1][i];
    for (i=1; i<=m; i++)
        s[n + 1][i]=n;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (i=1; i<=n; i++)    scanf("%d",&p[i]);
    for (i=1; i<=n; i++)
        for (j=i+1; j<=n; j++)
            dis[i][j]=dis[i][j - 1] + p[j] - p[(i + j) >> 1];
    Init();    
    for (j=2; j<=m; j++)
        for (i=n; i>j; i--)
            for (k=s[i][j - 1]; k<=s[i + 1][j]; k++)
            {
                int t=f[k][j - 1] + dis[k + 1][i];
                if (f[i][j] > t)
                {
                    f[i][j]=t;
                    s[i][j]=k;
                }
            }
    printf("%d",f[n][m]);
    return 0;
}