• hdu多校第一场1003 (hdu6580)Milk 背包


    题意:

    有一个n*m的矩阵,左右可以随便走,但只能在每一行的中点往下走,每走一格花费时间1.

    现在这个矩阵里放了k瓶牛奶,第i个牛奶喝下去需要ti时间

    起点是(1,1)

    对于每个i∈[1,k],问喝掉k瓶牛奶花费的最小时间

    题解:

    首先离散化行。

    记第 i 行的牛奶数为 ci,则对于第 i 行,求出在行内向左/右走喝 1,2,...,ci 包牛奶并 且回到/不回到行中点的最短时间,然后合并背包求出在第 i 行内喝 1,2,...,ci 包牛奶并且 回到/不回到行中点的最短时间,然后和在前 i−1 行喝牛奶并回到中点的背包合并,求出 在前 i 行内喝 1,2,...,k 包牛奶并且回到/不回到行中点的最短时间,并用不回到中点的背包 更新答案。每一行处理的复杂度为 O(kci),因此总复杂度为 O(k2)。

    注意对第一行因为是从最左边而不是中间开始,所以要特殊处理。

    #include<bits/stdc++.h>
    #define MAXN 10004
    #define LL long long
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    struct Milk{
        int x,y,t;
        friend bool operator >(const Milk &a,const Milk &b){
            return a.y>b.y;
        }
        friend bool operator <(const Milk &a,const Milk &b){
            return a.y<b.y;
        }
        
        Milk(){}
        Milk(int a,int b,int c){
            x=a;y=b;t=c;
        }
    }milk[MAXN];
    vector<LL> solve(const vector<Milk> &a,int dest){
        //调用引用,减小常数
        //背包算出停在dest点花费最小时间
        //若dest为0则不限制停在哪一点 
        vector<LL> c(a.size(),INF);
        vector<LL> t(a.size(),INF);
        c[0]=(dest==-1)?0:abs(dest-a[0].y);
        t[0]=0;
        for(int i=1;i<a.size();++i){
            int len=abs(a[i].y-a[i-1].y);
            for(int j=0;j<i;++j)t[j]+=len;
            for(int j=i;j>=1;--j)t[j]=min(t[j],t[j-1]+a[i].t);
            for(int j=0;j<=i;++j){
                LL tmp=t[j]+(dest==-1?0:abs(dest-a[i].y));
                c[j]=min(c[j],tmp);
            }
        }
        return c;
    }
    vector<LL> Merge(const vector<LL> &a,const vector<LL> &b){
        vector<LL> c(a.size()+b.size()-1,INF);
        for(int i=0;i<a.size();++i){
            for(int j=0;j<b.size();++j){
                c[i+j]=min(c[i+j],a[i]+b[j]);
            }
        }
        //两个参数分别是朝向两个方向喝多少瓶牛奶花费最少时间,把这俩合并 
        return c;
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            int n,m,k;
            scanf("%d %d %d",&n,&m,&k);
            vector<int> disc;
            disc.push_back(1);
            for(int i=1;i<=k;i++){
                scanf("%d %d %d",&milk[i].x,&milk[i].y,&milk[i].t);
                disc.push_back(milk[i].x);
            }
            sort(disc.begin(),disc.end());
            disc.erase(unique(disc.begin(),disc.end()),disc.end());
            //去重 
            vector<Milk> a[MAXN];
            LL Ans[MAXN];
            for(int i=0;i<disc.size();++i)a[i].clear();
            
            for(int i=1;i<=k;++i){
                int tmp=lower_bound(disc.begin(),disc.end(),milk[i].x)-disc.begin();
                a[tmp].push_back(milk[i]);
                Ans[i]=INF;
            }
            //将行离散化 
            for(int i=0;i<disc.size();++i){
                sort(a[i].begin(),a[i].end());
            } 
            vector<LL> f[2];//存储结果 
            vector<Milk> t=a[0];//存储当前行 
            
            t.insert(t.begin(),Milk(1,1,0));
            
            f[0]=solve(t,(m+1)/2);
            vector<LL> g=solve(t,-1);
            for(int i=0;i<t.size();++i)Ans[i]=min(Ans[i],g[i]);
            
            for(int i=1;i<disc.size();++i) {
                vector<Milk>::iterator sp=lower_bound(a[i].begin(),a[i].end(),Milk(i,(m+1)/2,0));
                vector<Milk> t0(a[i].begin(),sp);
                vector<Milk> t1(sp,a[i].end());
                
                t0.push_back(Milk(i,(m+1)/2,0));
                reverse(t0.begin(),t0.end()); 
                
                t1.insert(t1.begin(),Milk(i,(m+1)/2,0));
    
                vector<LL> f0,f1,g0,g1;
                f0=solve(t0,(m+1)/2);
                f1=solve(t1,(m+1)/2);
                g0=solve(t0,-1);
                g1=solve(t1,-1);
                //向两个方向分别背包 
                
                g0=Merge(f1,g0);
                g1=Merge(f0,g1);
                
    
                vector<LL> g(g0.size());
                
                for(int j=0;j<g.size();++j){
                    g[j]=min(g0[j],g1[j]);
                }
                    
                g=Merge(f[(i-1)&1],g);
                //把每层的背包合并 
    
                f[i&1]=Merge(f[(i-1)&1],Merge(f0,f1));
                
                for(int j=0;j<g.size();++j) {
                    Ans[j]=min(Ans[j],g[j]+=disc[i]-disc[i-1]);
                    f[i&1][j]+=disc[i]-disc[i-1];
                }
            }
            
            for(int i=1;i<k;i++){
                printf("%lld ",Ans[i]);
            }
            printf("%lld
    ",Ans[k]);
        }
    } 
  • 相关阅读:
    Swift开发第六篇——操作运算符也可以重载& func 的参数修饰
    Swift开发第五篇——四个知识点(Struct Mutable方法&Tuple&autoclosure&Optional Chain)
    Swift开发第四篇——柯里化
    Swift开发第三篇——Playground
    Swift开发第一篇——异常处理及断言
    在Linux CentOS 6.5 (Final)上安装git-1.9.0
    如何有效地配置基于Spring的应用系统
    关于URL编码的问题
    如何优化pom依赖项?
    启动Tomcat的几种方式
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11247195.html
Copyright © 2020-2023  润新知