标签:== src -o img 四边形不等式 amp 选中 复杂 转移
函数w满足
1: 区间包含的单调性,对于\(x1<x2<y1<y2\),有\(w[x2][y1] < w[x1][y2]\)
2: 四边形不等式,对于\(x1<x2<y1<y2\),有\(w[x1][y1]+w[x2][y2] < w[x1][y2]+w[x2][y1]\)
则函数m(其最优选择)也满足四边形不等式.
对于满足四边形不等式的函数,是满足单调性的(x方向单调,y方向也单调),可以通过判断dp是否满足四边形不等式,也可以用来优化转移区间
对于形如 \(dp[i][j] = min(dp[i][k]+dp[k+1][j])(i\leq k\leq j) + w[i][j]\) 的区间dp转移一般复杂度为O(n^3)的,
但若\(dp[i][j]\)满足四边形不等式,则其\(s[i][j]\)(使dp[i][j]最小的k)也满足四边形不等式,即可有O(n^2)的转移
\(dp[i][j] = min(dp[i][k]+dp[k+1][j])(s[i][j-1]\leq k\leq s[i+1][j])+w[i][j]\)
using namespace std;
const int N = 200+10;
int n;
int a[N],sum[N];
int dp[N][N],s[N][N];
int ans1 = 1<<30,ans2= 0;
int main(){
while(scanf("%d",&n)==1){
for(int i=1;i<=n;++i) scanf("%d",&a[i]),a[i+n]=a[i];
for(int i=1;i<=n*2;++i) sum[i] = sum[i-1]+a[i];
for(int i=1;i<=n*2;++i) dp[i][i]=0,s[i][i] = i;
for(int len=2;len<=n;++len){
for(int i=1;i+len-1<=n*2;++i){
int j = i+len-1;
dp[i][j] = 1<<30;
for(int k=s[i][j-1];k<=s[i+1][j];++k){
int val = dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1];
if(val < dp[i][j]){
dp[i][j] = val;
s[i][j] = k;
}
}
}
}
ans1 = dp[1][n];
for(int i=1;i<=n;++i) ans1 = min(ans1,dp[i][i+n-1]);
for(int i=1;i<=n*2;++i) dp[i][i]=0;
for(int len=2;len<=n;++len){
for(int i=1;i+len-1<=n*2;++i){
int j = i+len-1;
dp[i][j] = 0;
for(int k=i;k<j;++k){
int val = dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1];
if(val > dp[i][j]){
dp[i][j] = val;
}
}
}
}
ans2 = dp[1][n];
for(int i=1;i<=n;++i) ans2 = max(ans2,dp[i][i+n-1]);
printf("%d\n%d\n",ans1,ans2);
}
return 0;
}
当前dis可以通过前一个dis和当前点位置O(1)计算出
const int N = 300+10, M = 32;
int n,m,pos[N],dis[N][N]; // i到j选一个点作为邮局最短距离
int dp[N][M],s[N][M]; // 1到i选j个点作为邮局的最短距离,和最优转移点
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&pos[i]);
for(int i=1;i<=n;++i){
dis[i][i] = 0;
for(int j=i+1;j<=n;++j){ // 两点之间肯定要选中位数所在点
dis[i][j] = dis[i][j-1] + pos[j] - pos[(i+j)>>1]; // dis只增加了右端点到中间点的距离
}
}
for(int i=1;i<=n;++i)
dp[i][1] = dis[1][i],s[i][1] = 0; // 初始化 1到i选一个点的最短距离即为 dis[1][i], 而只选了一个点没有转移点
// s[j][i-1] <= s[j][i] <= s[j+1][i] j从大到小,i从小到大
for(int i=2;i<=m;++i){ // 当前选了几个点
s[n+1][i] = n; // 这个值不会被计算,但要被用到,赋为n
for(int j=n;j>i;--j){ // 当前有几个房子
dp[j][i] = 1<<30;
for(int k=s[j][i-1];k<=s[j+1][i];++k){
int val = dp[k][i-1] + dis[k+1][j];
if(dp[j][i]> val) dp[j][i] = val, s[j][i] = k;
}
}
}
printf("%d\n",dp[n][m]);
}
POJ 1160 Post Office(四边形不等式优化)
标签:== src -o img 四边形不等式 amp 选中 复杂 转移
原文地址:https://www.cnblogs.com/xxrlz/p/11449466.html