zoukankan      html  css  js  c++  java
  • HDU 2829 四边形不等式优化

    题目大意:给定一个长度为n的序列,至多将序列分成m段,每段序列都有权值,权值为序列内任意两个数两两相乘之和。m<=n<=1000. 令权值最小。

    dp[i][j]=max{dp[i][j],dp[i-1][k]+w[k+1][j]},遍历k.dp[i][j]表示将前j个分为i段,w[k+1][j]表示k+1到j为一段的权值。

    用四边形不等式不等式可以进行优化从n^3变成n^2,具体原理还是参考百度,这里只提一下基本的思路;

    设m[i,j]表示动态规划的状态量。

    m[i,j]有类似如下的状态转移方程:

    m[i,j]=opt{m[i,k]+m[k,j]}(i≤k≤j)

    如果对于任意的a≤b≤c≤d,有m[a,c]+m[b,d]≤m[a,d]+m[b,c],那么m[i,j]满足四边形不等式。

    对于这题:

    转移方程dp[i][j]=min(dp[i-1][k]+w[k+1][j])(i-1<k<j),cost[i][j+1]-cost[i][j]>0 满足四边形不等式优化的条件

    则可以进行优化,至于优化过程因为还没理解,照抄以下,注意for循环范围即等于号,这样求得的即是最小值

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <math.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    using namespace std;
    typedef long long ll;
    const int N = 1000;
    const int mod=1e9+7;
    const double en=2.718281828459;
    using namespace std;
    #define inf (ll)1<<60
    ll dp[1002][1002];
    ll w[1002][1002];
    ll s[1002][1002];
    ll p[1002];
    ll val[1002][1002];
    int n,m;
    int main() {
     //freopen("in.txt","r",stdin);
        while(~scanf("%d%d",&n,&m)){
            memset(val,0,sizeof(val));
            memset(w,0,sizeof(w));
            memset(dp,0,sizeof(dp));
            if(n==0&&n==m)
                break;
            int i,j;
            for(i=1;i<=n;i++)
                scanf("%lld",&p[i]);
            for(i=1;i<n;i++)
                for(j=i+1;j<=n;j++)
                    val[i][j]=val[i][j-1]+p[i]*p[j];
            for(i=n-1;i>=1;i--)
                for(j=i+1;j<=n;j++)
                    w[i][j]=w[i+1][j]+val[i][j];//直到这里求出了需要求的w
            for(i=1;i<=m+1;i++)
                for(j=i+1;j<=n;j++)
                    dp[i][j]=inf;
            for(i=1;i<=n;i++){
                dp[1][i]=w[1][i];
                s[1][i]=0;
            }
            for(i=2;i<=m+1;i++){//注意是m+1
                s[i][n+1]=n;
                for(j=n;j>i;j--){
                    for(int k=s[i-1][j];k<=s[i][j+1];k++){
                    ll tmp=dp[i-1][k]+w[k+1][j];
                    if(tmp<dp[i][j]){
                           dp[i][j]=tmp;
                            s[i][j]=k;
    
                    }
    
                    }
    
                }
    
            }
            if(n<=m+1) printf("0
    ");
            else printf("%lld
    ",dp[m+1][n]);
    
        }
        return 0;
    }
    
  • 相关阅读:
    Intellij 常用技巧-持续更新
    Android界面组件的四种启动方式
    Preference Screen 首选项
    Oracle OCI-22053:溢出错误
    SQLPLUS使用
    Oracle中数字格式的文本化处理
    MP4V2 移植 (基于imx6 平台)
    IMX6Q camera 应用编程之 摄像头裁剪
    IMX6Q camera驱动分析 (4)
    IMX6Q Camera驱动分析 (3)
  • 原文地址:https://www.cnblogs.com/shimu/p/5746036.html
Copyright © 2011-2022 走看看