POJ 1160 dp + 四边形优化

来源:互联网 发布:腾讯云数据库怎么连接 编辑:程序博客网 时间:2024/05/20 00:38

一、四边形不等式基本理论

在动态规划的转移方程中,常见这样一种转移方程:

这两个定理证明在赵爽的《动态规划加速原理之四边形不等式》中给出了相关的证明。


【题意】给出m个村庄及其距离,给出n个邮局,要求怎么建n个邮局使代价最小.

【分析】

dp(i,j)=min(dp(i-1,k)+w(k+1,j)) , i-1<=k<j  s(i-1,j)<=k<=s(i,j+1)

w(i,j)=w(i,j-1)+val[j]-val[(j+i)/2] , i<j<=n

dp(1,i)=w(1,i), w(i,i)=0, s(1,i)=0

对于函数w(i,j)有人可能疑问,从ij建一座邮局,对于邮局位置k,(i<=k<=j),这是一个凹区间,k选在i ,j的中间位置w(i,j)才是最小的,如何j-i是一个奇数,那么中间的两个数都是距离最小的点。对于w满足四边形不等式和区间单调性(本人表示不大会证,一般动态转移方程类似,n^3不能解决的问题,都是这么搞吧)。于是,我们限制了原方程中k的取值范围,得到了O(n^2)算法。

【AC代码】

#include <iostream>#include <cstdio>using namespace std;#define inf 0x7ffffff#define MIN(a,b) ((a)<(b)?(a):(b))int dp[31][301];int val[301];int w[301][301];int s[31][301];//表示前i-1个邮局的城市数int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        for(int i=1; i<=n; ++i)        {            scanf("%d",&val[i]);        }        for(int i=1; i<=n; ++i)        {            w[i][i]=0;            for(int j=i+1; j<=n; ++j)            {                w[i][j]=w[i][j-1]+val[j]-val[(i+j)/2];            }        }        //init1.        for(int i=1; i<=n; ++i)        {            for(int j=1; j<=m; ++j)            {                dp[j][i]=inf;            }        }        //init2.        for(int i=1; i<=n; ++i)        {            dp[1][i]=w[1][i];            s[1][i]=0;        }        //dp.        for(int i=2; i<=m; ++i)        {            s[i][n+1]=n;//s[i][j]定义为使得dp(i,j)对应的决策的最大值            for(int j=n; j>i; --j)            {                for(int k=s[i-1][j]; k<=s[i][j+1]; ++k)//四边形优化                {                    if(dp[i-1][k]+w[k+1][j]<dp[i][j])                    {                        s[i][j]=k;                    }                    dp[i][j]=MIN(dp[i][j],dp[i-1][k]+w[k+1][j]);                }            }        }        printf("%d\n",dp[m][n]);    }    return 0;}


1 0
原创粉丝点击