zoukankan      html  css  js  c++  java
  • 对测 【离线DP+二分】

    本人水平有限,题解不到为处,请多多谅解

     本蒟蒻谢谢大家观看

    题目:

    Market
    (market.c/cpp/pas)
    Input fifile: market.in
    Output fifile: market.out
    Time limit: 1 seconds
    Memory limit: 128 megabytes
    在比特镇一共有 n 家商店,编号依次为 1 到 n。每家商店只会卖一种物品,其中第 i 家商店的物品
    单价为 ci,价值为 vi,且该商店开张的时间为 ti。
    Byteasar 计划进行 m 次购物,其中第 i 次购物的时间为 Ti,预算为 Mi。每次购物的时候,Byteasar
    会在每家商店购买最多一件物品,当然他也可以选择什么都不买。如果购物的时间早于商店开张的时间,
    那么显然他无法在这家商店进行购物。
    现在 Byteasar 想知道,对于每个计划,他最多能购入总价值多少的物品。请写一个程序,帮助
    Byteasar 合理安排购物计划。
    注意:每次所花金额不得超过预算,预算也不一定要花完,同时预算不能留给其它计划使用。
    Input
    第一行包含两个正整数 n, m,表示商店的总数和计划购物的次数。
    接下来 n 行,每行三个正整数 ci , vi , ti,分别表示每家商店的单价、价值以及开张时间。
    接下来 m 行,每行两个正整数 Ti , Mi,分别表示每个购物计划的时间和预算。
    Output
    输出 m 行,每行一个整数,对于每个计划输出最大可能的价值和。
    Examples
    market.in market.out
     
    输入
    5 2
    5 5 4
    1 3 1
    3 4 3
    6 2 2
    4 3 2
    3 8
    5 9
    输出
    10
    12
    第一个计划可以在商店 2,3,5 各购买一件物品,总花费为 1 + 3 + 4 = 8,总价值为 3 + 4 + 3 = 10。
    第二个计划可以在商店 1,2,3 各购买一件物品,总花费为 5 + 1 + 3 = 9,总价值为 5 + 3 + 4 = 12。
     
     
    40分算法
    直接背包 把总花费当做容量,总价值当做val ,再特判一下时间即可
    设 f[] 为容量小于等于Mi 的最大价值和
    code:
    #include<bits/stdc++.h>
    #pragma GCC optimize(3)
    using namespace std;
    int n,m,sum=0,ans=0;
    int f[1000001];
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*f;
    }
    struct oo{
        int c,v,t;
    }a[100010];
    struct node{
        int tt,mm,id;
    }b[100010];
    bool cmp(oo a,oo b){
        return a.t<b.t;
    }
    bool comp(node a,node b){
        return a.tt<b.tt;
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++){
            a[i].c=read(),a[i].v=read(),a[i].t=read();
            sum+=a[i].c;
        }
        for(int i=1;i<=m;i++){
            b[i].tt=read(),b[i].mm=read();
            b[i].id=i;
        }
        sort(a+1,a+n+1,cmp);
        //sort(b+1,b+m+1,comp);
        //f[0][0]=0;
                f[0]=0;
        for(int j=1;j<=m;j++){
            memset(f,0,sizeof(f));
            for(int i=1;i<=n;i++){
                if(a[i].t<=b[j].tt){
                    for(int kk=b[j].mm;kk>=a[i].c;kk--){
                        f[kk]=max(f[kk],f[kk-a[i].c]+a[i].v);
            
            //        cout<<"f[i][kk]= "<<f[i][kk]<<" i= "<<i<<" kk= "<<kk<<endl;
                    }
                }
                //ans+=f[n][b[j].mm];
            }
            printf("%d
    ",f[b[j].mm]);
        }
        return 0;
    }
    /*
    5 2
    5 5 4
    1 3 1
    3 4 3
    6 2 2
    4 3 2
    3 8
    5 9
    */

    100分做法:离线DP+二分

    c[i](花费)很大但v[i](获得的价值)很小,

    f[j]表示获利恰好为j时,所用的最小化费(初始设为正无穷)

    方程f[j]=min(f[j],f[j-v[i]]+c[i])

    于是对于每一个询问M,直接从后往前扫描,找到第一个小于等于M的值,其下标就是答案

    这里这么设置主要是因为考虑到60%时候的方程,当M变大时,v依然很小,于是考虑把下标和数组的值更换一下位置
     
     
    code:
    #include<bits/stdc++.h>
    #pragma GCC optimize(3)
    #define N 503
    #define LL long long
    using namespace std;
    int n,m,ans[100003];
    LL f[N*N];
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*f;
    }
    struct data{
            int c,v,t,pos,num;
    }b[100003],a[N],c[N];
    int cmp(data a,data b){
        return a.t<b.t||a.t==b.t&&a.c>b.c;
    }
    int cmp1(data a,data b){
        return a.pos<b.pos||a.pos==b.pos&&a.c>b.c;
    }
    int calc(int x){
        int l=1;
        int r=n;
        int ans=0;
        while (l<=r){
            int mid=(l+r)/2;
             if (a[mid].t<=x){
                 ans=max(ans,mid);
                 l=mid+1;
             }
             else{
                 r=mid-1;
             }
        }
        return ans;
    }
    int main(){
        n=read(),m=read();
        int sum=0;
        for (int i=1;i<=n;i++)
            a[i].c=read(),a[i].v=read(),a[i].t=read(),sum+=a[i].v;
        sort(a+1,a+n+1,cmp);
        for (int i=1;i<=m;i++)
            b[i].t=read(),b[i].c=read(),b[i].num=i;
        for (int i=1;i<=m;i++)
            b[i].pos=calc(b[i].t);
        sort(b+1,b+m+1,cmp1);
        int t=1;
        while (!b[t].pos&&t<=m)
            t++;
        memset(f,127,sizeof(f));
        LL inf=f[0];
        f[0]=0;
        for (int i=1;i<=n;i++){
            for (int j=sum;j>=a[i].v;j--)
                f[j]=min(f[j],f[j-a[i].v]+(LL)a[i].c);
        int last=sum;
        while (b[t].pos==i&&t<=m){
            for (int j=last;j>=1;j--)
                if (f[j]<=b[t].c){
                    ans[b[t].num]=j;
                    last=j;
                    break;
                }
                t++;
            }
        }
            for (int i=1;i<=m;i++)
                printf("%d
    ",ans[i]);
            return 0;
    }
     
     
     
     
  • 相关阅读:
    iOS CoreData使用笔记
    iOS UIWebView中添加手势
    Swift sha1 md5加密
    Swift用block响应UIAlertView和UIActionSheet的按钮点击事件
    iOS判断iPhone型号
    iOS Document Interaction 编程指南
    Swift项目开发中缓存计算以及清除
    SVN 一次性提交多个目录中文件
    svn 相关
    sublime text 2相关
  • 原文地址:https://www.cnblogs.com/nlyzl/p/11561804.html
Copyright © 2011-2022 走看看