zoukankan      html  css  js  c++  java
  • HDU 2829 Lawrence(四边形优化DP O(n^2))

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2829

    题目大意:有一段铁路有n个站,每个站可以往其他站运送粮草,现在要炸掉m条路使得粮草补给最小,粮草补给的公式是将每个站能收到的粮草的总和。

    4----5-----1-----2

    粮草总和为4*5 + 4*1 + 4*2 + 5*1 + 5*2 + 1*2 = 49.

    4----5       1-----2

    粮草总和为4*5 + 1*2 = 22. 

    4      5-----1------2

    粮草总和为5*1 + 5*2 + 1*2 = 17.

    解题思路:参考,状态转移方程为dp[i][j]=min{dp[k][j-1]+cost[k+1][i]}(k<i),若cost[i][j]满足凸四边形不等式,则可以用四边形优化。

         这里我们有一个定理:cost为凸当且仅当 cost[i][j] + cost[i+1][j+1] <= cost[i+1][j] + cost[i][j+1]。

         我们可以把原式cost[i][j] + cost[i'][j'] <= cost[i][j'] + cost[i'][j]变为cost[i + 1][j + 1] - cost[i + 1][j] <= cost[i][j + 1] - cost[i][j],然后固定j变化i,看coat[i][j+1] - cost[i][j]是关于i递增还是递减,如果是递减,则cost为凸。

         一般如果不能直接看出来,可以进行打表。此题cost[i][j]满足该定理,于是可以用四边形优化将复杂度降至O(n^2)。

         注意:这里的是s[i][j]处理跟石子归并时不一样,还有i是倒着来的,不是正着的。

    代码:

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 typedef long long LL;
     5 const int N=1e3+5;
     6 const long long INF=0x3f3f3f3f;
     7 LL sum[N],dp[N][N],cost[N][N],s[N][N];//s[i][j]记录dp[i][j]的最优切割点 
     8 
     9 int main(){
    10     int n,m;
    11     while(~scanf("%d%d",&n,&m)){
    12         if(n==0&&m==0)
    13             break;
    14         memset(cost,0,sizeof(cost));
    15         memset(dp,INF,sizeof(dp));
    16         for(int i=1;i<=n;i++){
    17             scanf("%lld",&sum[i]);
    18             sum[i]+=sum[i-1];
    19             s[i][0]=0;
    20         }
    21         //计算cost[i][j]
    22         for(int i=1;i<=n;i++){
    23             for(int j=1;j<i;j++){
    24                 cost[1][i]+=(sum[j]-sum[j-1])*(sum[i]-sum[j]);
    25             }
    26             dp[i][0]=cost[1][i];
    27         }
    28         for(int k=1;k<=n;k++){
    29             for(int i=k+1;i<=n;i++){
    30                 cost[k][i]=cost[1][i]-cost[1][k-1]-sum[k-1]*(sum[i]-sum[k-1]);
    31             }
    32         }
    33         
    34         //j为轰炸次数,当i = 1或者j = n时为边界对s的处理就是为了处理这些边界
    35         for(int j=1;j<=m;j++){
    36             s[n+1][j]=n-1;
    37             for(int i=n;i>=j;i--){
    38                 for(int k=s[i][j-1];k<=s[i+1][j];k++){
    39                     LL tmp=dp[k][j-1]+cost[k+1][i];            
    40                     if(tmp<dp[i][j]){
    41                         dp[i][j]=tmp;
    42                         s[i][j]=k;
    43                     }
    44                 }
    45             }    
    46         }
    47         printf("%lld
    ",dp[n][m]);
    48     }
    49     return 0;
    50 }
  • 相关阅读:
    Storm集群环境搭建
    如何使用Python进行投资收益和风险分析
    [项目源码] JavaWeb校园宿舍管理系统
    (null) entry in command string: null chmod 0644
    Ubuntu设置代理服务器
    ZooKeeper异常:Error connecting service It is probably not running
    MySQL绿色版安装
    Pig关系型运算符例子
    pig分组统计例子
    java服务端项目开发规范
  • 原文地址:https://www.cnblogs.com/fu3638/p/7822935.html
Copyright © 2011-2022 走看看