四边形不等式

来源:互联网 发布:神州律师网网络培训 编辑:程序博客网 时间:2024/04/29 21:08

总结一下最近几天对dp优化中的四边形不等式的学习。

证明什么的似懂非懂,我还是太年轻了。

第一种, n^2 -> nlogn

例题:http://wzoi.cc/s/1370/1304  (由于权限问题 不公开题面)

就是1个体积均为1-300,100000个物品,做一个100000的背包。

发现体积最多只有 300 种,分开做。对于同种体积的物品,显然按照价值从大到小取最优。

我们假设 s=1,设状态 f[i]为大小为 i的背包的最大收益。

转移函数 f[i]=max(f[ i-j ]+sum(a[1..j]))

是一个  f[x]=min{f[i]+w[i,x]}的经典模型

w满足大区间大于等于小区间的性质,

且当 a<b<c<d时,w[a,c]+w[b,d]<=w[a,d]+w[b,c],

于是 决策有单调性 ,假如用 k(x)表示状态x 取到最优值时的决策 , k(x) 是不降的。

注意到给定两个决策点,我们是可以通过二分计算出令他们大小关系反转的时间点 t 的。

于是就可以维护一个单调栈,进行二分。

对于其他的 s,发现只有在状态模 s 同余时单调性才成立,所以对于每一种体积 s,按照剩余类的顺序依次做即可。

时间复杂度 O(MAXS*K+N)


code :

#include<bits/stdc++.h>using namespace std;typedef long long ll;#define rep(i,l,r) for(int i=l;i<=r;++i)#define per(i,r,l) for(int i=r;i>=l;--i)template <typename T> void chmin(T &x,const T &y){if(x>y)x=y;}template <typename T> void chmax(T &x,const T &y){if(x<y)x=y;}const int N=1e6+5,M=1e5+5,S=300+5;ll dp[S][M];int t[S];struct edge{int v,next;}l[N];ll val[N];int q[N],top;int st[N],can[N],head,tail;int s,d,mi,i;ll get(int j,int i){return dp[s-1][j*s+d]+val[i-j];}bool you(int j,int k){return get(i,k)>=get(j,k);}#define mid (l+r>>1)int erfen(){if(head==tail) return i;int j=st[tail-1];int l=can[tail-1],r=mi;while(l+1!=r) if(you(j,mid)) r=mid;else l=mid;return r;}int main(){//freopen("1.in","r",stdin);freopen("1.out","w",stdout);int n,m;cin>>n>>m;rep(i,1,n){int s;scanf("%d%d",&s,&l[i].v);l[i].next=t[s];t[s]=i;}dp[0][0]=0;for(s=1;s<=300;++s){if(!t[s]){memcpy(dp[s],dp[s-1],sizeof(dp[s]));continue;}top=0;for(int i=t[s];i;i=l[i].next) q[++top]=l[i].v;sort(q+1,q+top+1,greater<int>() );rep(i,1,top)val[i]=val[i-1]+q[i];rep(i,top+1,m)val[i]=0;for(d=0;d<s;++d){mi=(m-d)/s;head=1;tail=0;for(i=0;i<=mi;++i){while(head<tail&&can[head+1]<=i)++head;if(can[head]<i)can[head]=i;while(head<=tail&&you(st[tail],can[tail]))--tail;if(head>tail){st[++tail]=i;can[tail]=i;}elseif(you(st[tail],mi)){st[++tail]=i;can[tail]=erfen();}dp[s][i*s+d]=get(st[head],i);}}}rep(i,1,m)printf("%lld ",dp[300][i]);}

第二种:n^3-> n^2


(1)区间包含的单调性:如果对于i≤i'<j≤j',有w(i',j)≤w(i,j'),那么说明w具有区间包含的单调性。(可以形象理解为如果小区间包含于大区间中,那么小区间的w值不超过大区间的w值)

(2)四边形不等式:如果对于i≤i'<j≤j',有w(i,j)+w(i',j')≤w(i',j)+w(i,j'),我们称函数w满足四边形不等式。(可以形象理解为两个交错区间的w的和不超过小区间与大区间的w的和)

下面给出两个定理

定理一:如果上述的w函数同时满足区间包含单调性和四边形不等式性质,那么函数m也满足四边形不等式性质。


我们再定义s(i,j)表示m(i,j)取得最优值时对应的下标(即i≤k≤j时,k处的w值最大,则s(i,j)=k)。此时有如下定理

定理二:假如m(i,j)满足四边形不等式,那么s(i,j)单调,即s(i,j)≤s(i,j+1)≤s(i+1,j+1)。


例题:  poj1160


code


#include<stdio.h>#include<string.h>#define MAXD 310#define MAXP 40#define INF 0x3f3f3f3fint N, P, f[MAXD][MAXD], A[MAXD], a[MAXD], K[MAXD][MAXD];void init(){    int i, j, k;    A[0] = 0;    for(i = 1; i <= N; i ++)    {        scanf("%d", &a[i]);        A[i] = A[i - 1] + a[i];    }}int getw(int x, int y){    int t = (x + y) / 2;    return A[y] - A[t] - (y - t) * a[t] + (t - x) * a[t] - (A[t - 1] - A[x - 1]);}void solve(){    int i, j, k, p, t;    for(i = 0; i <= N; i ++)    {        f[i][i] = 0;        K[i][i] = i;    }    for(p = 1; p <= N - P; p ++)    {        for(i = 0; (j = i + p) <= N; i ++)            f[i][j] = INF;        for(i = 1; (j = i + p) <= N; i ++)        {            for(k = K[i][j - 1]; k <= K[i + 1][j]; k ++)                if((t = f[i - 1][k - 1] + getw(k, j)) < f[i][j])                {                    f[i][j] = t;                    K[i][j] = k;                }        }    }    printf("%d\n", f[P][N]);}int main(){    while(scanf("%d%d", &N, &P) == 2)    {        init();        solve();    }    return 0;}

本来无法理解三重循环为何n^2,后来模拟了一遍,

从小区间推向大区间即从dp方阵的每条对角线(好吧不是对角线 就是表达那个意思)从中间向两边转移,

,每条对角线的转移时O(n)的,然后有O(n)条对角线,于是就O(n^2)了,太神了%%%。

原创粉丝点击