标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 327680/327680 K (Java/Others)
Total Submission(s): 4479 Accepted Submission(s): 812
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define maxn 50100 #define LL long long #define inf 0x3f3f3f3f3f3f3f3f3f3f using namespace std; LL dp[maxn][200]; int que[maxn]; int n,k; int head,tail; struct node { LL w; LL h; }; node p[maxn]; bool cmp(node a,node b) { if(a.w==b.w) return a.h<b.h; else return a.w>b.w; } LL getdp(int i,int j,int k) { //return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]); return dp[k][j-1]+p[k+1].w*p[i].h; } LL getup(int j,int k1,int k2) //yj-yk部分 k1>k2 { //return dp[j]+sum[j]*sum[j]-(dp[k]+sum[k]*sum[k]); return dp[k1][j-1]-dp[k2][j-1]; } LL getdown(int j,int k1,int k2) { //return 2*(sum[j]-sum[k]); return p[k2+1].w-p[k1+1].w; } void solve() { head=0; tail=0; que[tail++]=0; dp[0][0]=0; for(int i=1;i<=n;i++) { dp[i][0]=inf; dp[0][i]=0; } for(int j=1;j<=k;j++) { head=tail=0; que[tail++]=0; for(int i=1;i<=n;i++) { //从头开始找当前状态的最优决策,g[que[head+1],que[head]] < sum[i],说明que[head+1]比que[head]更优,删除que[head] while(head+1 < tail && getup(j,que[head+1],que[head]) <= getdown(j,que[head+1],que[head]) * p[i].h ) head++; //注意写成相乘,不然要考虑除数是否为负数 dp[i][j]=getdp(i,j,que[head]); //从尾往前,加入当前状态,如果g[i,que[tail]] < g[que[tail],que[tail-1]] ,可以排除que[tail] while(head+1<tail && getup(j,i,que[tail-1])*getdown(j,que[tail-1],que[tail-2])<=getup(j,que[tail-1],que[tail-2])*getdown(j,i,que[tail-1])) tail--; que[tail++]=i; } } /*for(int j=1;j<=k;j++) { for(int i=1;i<=n;i++) printf("%lld ",dp[i][j]); printf("\n"); }*/ printf("%lld\n",dp[n][k]); } int main() { while(~scanf("%d%d",&n,&k)) { //init(); for(int i=1;i<=n;i++) scanf("%lld%lld",&p[i].w,&p[i].h); sort(p+1,p+n+1,cmp); int j=1; for(int i=2;i<=n;i++) { if(p[i].h<p[j].h) continue; else { p[++j]=p[i]; } } n=j; //for(int i=1;i<=n;i++) // printf("%lld %lld\n",p[i].w,p[i].h); solve(); } return 0; }
四边形优化:
目前位置接触到两种形式的方程可以采用四边形优化:
1
a d[i][j]=min(d[i-1][k]+p[k+1].w*p[i].h)
写成这种形式,而不是上面那种,是因为四边形优化的s[i][j]的递推顺序好写
b s[i-1][j]<s[i][j]<s[i][j+1];
观察a和b式,i从小到大,j从大到小.然后初始化第一行和第n+1列,进行递推。
2 (类似于石子合并)
d[i][j]=d[i][k]+d[k+1][j]+w[i][j]
s[i][j-1]<s[i][j]<s[i+1][j]
这时候的递推顺序,是通过先枚举长度,再枚举起点,然后就可以现在要算的状态之前都算过了。
(超时代码,目前只能写到这了)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define maxn 50100 #define LL long long #define inf 0x3f3f3f3f3f3f3f3f3f3f using namespace std; LL d[maxn][200]; int w[maxn][200]; int n,k; struct node { LL w; LL h; }; node p[maxn]; bool cmp(node a,node b) { if(a.w==b.w) return a.h<b.h; else return a.w>b.w; } void solve() { for(int i=1;i<=n;i++) { d[1][i]=p[1].w*p[i].h; w[1][i]=0; } for(int i=2;i<=k;i++) { w[i][n+1]=n; for(int j=n;j>=i;j--) { d[i][j]=inf; for(int s=w[i-1][j];s<=w[i][j+1];s++) { if(d[i][j]>(d[i-1][s]+p[s+1].w*p[j].h) ) { d[i][j]=(d[i-1][s]+p[s+1].w*p[j].h); w[i][j]=s; } } } } /*for(int i=0;i<=k;i++) { for(int j=0;j<=n+1;j++) printf("%d ",w[i][j]); printf("\n"); } printf("\n"); for(int i=0;i<=k;i++) { for(int j=0;j<=n;j++) printf("%lld ",d[i][j]); printf("\n"); }*/ printf("%lld\n",d[k][n]); } int main() { while(~scanf("%d%d",&n,&k)) { //init(); memset(d,0,sizeof(d)); for(int i=1;i<=n;i++) scanf("%lld%lld",&p[i].w,&p[i].h); sort(p+1,p+n+1,cmp); int j=1; for(int i=2;i<=n;i++) { if(p[i].h<p[j].h) continue; else { p[++j]=p[i]; } } n=j; solve(); } return 0; }
标签:
原文地址:http://www.cnblogs.com/xianbin7/p/4519966.html