POJ-1160 Post Office (DP+四边形不等式优化)

题目大意:有v个村庄成直线排列,要建设p个邮局,为了使每一个村庄到离它最近的邮局的距离之和最小,应该怎样分配邮局的建设,输出最小距离和。

题目分析:定义状态dp(i,j)表示建设 i 个邮局最远覆盖到第 j 个村庄时最小距离和。容易得到dp(i,j)=min(dp(i-1,k-1)+w(k,j)),其中w(k,j)表示在k~j之间建设一个邮局的最小距离,所以很显然w(i,j)关于包含关系单调,可以看出w(i,j)还满足凸四边形不等式,所以dp(i,j)也满足凸四边形不等式。那么就有K(i,j-1)<=K(i,j)<=K(i+1,j),也就能通过限定k的取值范围达到优化的效果。其实这道题数据规模不大,不加优化也能AC。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;

const int INF=1<<30;

int v,p;
int dp[305][305];
int K[305][305];
int x[305],s[305];

void read()
{
    s[0]=0;
    for(int i=1;i<=v;++i){
        scanf("%d",x+i);
        s[i]=x[i]+s[i-1];
    }
}

int getw(int a,int b)
{
    int m=(a+b)>>1;
    return s[b]-s[m]-x[m]*(a+b-2*m)-s[m-1]+s[a-1];
}

void solve()
{
    for(int i=1;i<=v;++i){
        dp[i][i]=0;
        dp[0][i]=INF;
        K[i][i]=i;
    }
    for(int l=2;l<=v-p+1;++l){
        for(int i=1;i+l-1<=v;++i){
            int j=i+l-1;
            dp[i][j]=INF;
            int temp;
            for(int k=K[i][j-1];k<=K[i+1][j];++k){
                if(dp[i][j]>(temp=dp[i-1][k-1]+getw(k,j))){
                    dp[i][j]=temp;
                    K[i][j]=k;
                }
            }
        }
    }
    printf("%d\n",dp[p][v]);
}

int main()
{
    while(~scanf("%d%d",&v,&p))
    {
        read();
        solve();
    }
    return 0;
}

  

你可能感兴趣的:(POJ-1160 Post Office (DP+四边形不等式优化))