一、四边形不等式基本理论
在动态规划的转移方程中,常见这样一种转移方程:
这两个定理证明在赵爽的《动态规划加速原理之四边形不等式》中给出了相关的证明。
【题意】给出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)有人可能疑问,从i到j建一座邮局,对于邮局位置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; }