zoukankan      html  css  js  c++  java
  • 01背包

    【题目描述】

           有一个容量为W的背包,有N种物品,第i种物品的体积为Ti,价值为Vi

           对于每种物品,你可以选择是否将它放入背包,放入背包的物品的总体积不能超过W,在这个前提下你希望放入背包的物品的总价值最大。

    【输入数据】

           第一行两个数W,N,表示背包的容量和物品的数量。

           之后N行,每行两个数Ti,Vi,表示第i件物品的体积和价值。

    【输出数据】

           输出一个数,放入背包的物品的最大总价值。

    【样例】

    bag.in

    bag.out

    9 3

    7 14

    5 9

    4 7

    16

    【数据规模】

    前边30%的数据:   n≤20    w≤100000000  3个数据;

    中间40%的数据:   n≤300   w≤100000000  6个数据;

    后面30%的数据:   300<n≤1000  w≤10000  3个数据。

    【数据提示】

    数据保证随机。

    题目分析:

      题意简单,好像是动规中的01背包问题。

    01背包的时间复杂度O(nV)或者O(nw),这样好像只能得30分。

    怎么办呢?题目中好像只有n比较小,能不能想办法从n下手?

    没有别的办法就搜吧,注意加上搜索的优化和卡时。

    首先预处理数据

    (1)按性价比从高到底的顺序对物品排序;

    (2)贪心求出最大值;

    (3)求后i项的价值总和,搜索优化用;

    (4)求后i项最小的体积,搜索优化用。

    搜索:

        为了防止超时,要记录搜索运行的次数,当次数<=50000000时,可以继续搜,否则果断结束,输出当前结果

    var v,w,sumv,minw:array[1..1000]of int64;
        f:array[0..10000]of int64;
        m,n,i,j,ans,nowmax,tot:longint;//time,ttime:double;
    
    procedure init;
    var i:longint;
    begin
      assign(input,'bag.in');reset(input);
      assign(output,'bag.out');rewrite(output);
      readln(m,n);
      for i:=1 to n do begin
        readln(w[i],v[i]);
      end;
      
    end;
    
    procedure qsort(l,r:longint);//按性价比从高到低排序
    var i,j,t:longint;x:double;
    begin
      i:=l;j:=r;x:=v[(l+r) shr 1]/w[(l+r) shr 1];
      repeat
        while v[i]/w[i]>x+1e-7 do inc(i);
        while v[j]/w[j]<x-1e-7 do dec(j);
        if i<=j then begin
          t:=w[i];w[i]:=w[j];w[j]:=t;t:=v[i];v[i]:=v[j];v[j]:=t;
          inc(i);dec(j);
        end;
      until i>j;
      if j>l then qsort(l,j);if i<r then qsort(i,r);
    end;
    
    function min(a,b:longint):longint;
    begin if a<b then exit(a) else exit(b) end;
    
    function max(a,b:longint):longint;
    begin if a>b then exit(a) else exit(b) end;
    
    procedure dfs_predeal;
    var i,t:longint;
    begin
      qsort(1,n);
      i:=0;t:=m;ans:=0;nowmax:=0;tot:=0;
      for i:=1 to n do if w[i]<=t then begin
        dec(t,w[i]);inc(ans,v[i]);
      end;//贪心法求得最大值
      for i:=n downto 1 do sumv[i]:=sumv[i+1]+v[i];{//求后i项的价值总和,搜索优化用}
      minw[n+1]:=maxlongint;
      for i:=n downto 1 do minw[i]:=min(minw[i+1],w[i]);{求后i项最小的体积,搜索优化用}
    end;
    
    procedure dfs(i,mm:longint);//考虑第i件物品,当前剩余体积为mm
    begin
      if minw[i]>mm then begin//如果后i件物品中最小的体积都大于mm
        if nowmax>ans then ans:=nowmax;
        exit;
      end;
      if nowmax+sumv[i]<=ans then exit;{如果加上剩余i件物品的价值总和,还小于当前的最优值}
      inc(tot);if tot>50000000 then begin
        writeln(ans);close(output);halt;
      end;
      if mm>=w[i] then begin
        inc(nowmax,v[i]);//选第i件物品
        dfs(i+1,mm-w[i]);
        dec(nowmax,v[i]);//回溯
      end;
      dfs(i+1,mm);
    end;
    
    procedure dp;
    begin
      fillchar(f,sizeof(f),0);
      for i:=1 to n do
        for j:=m downto w[i] do
          f[j]:=max(f[j],f[j-w[i]]+v[i]);
      ans:=f[m];
    end;
    
    begin
      init;
      if (m>10000) then begin
        dfs_predeal;
        dfs(1,m);
      end else dp;
      writeln(ans);
      close(output);
    end.
    View Code
  • 相关阅读:
    javascript之void0
    Sublime之OS X Command Line
    iOS之Monkey
    iOS之在成员函数中使用Block
    mac之javascriptcore
    国内成功码农的发展轨迹
    HTML之表格初步
    ClientSide JavaScript Timeline
    javascript正则表达式
    同源策略
  • 原文地址:https://www.cnblogs.com/ssfzmfy/p/4033205.html
Copyright © 2011-2022 走看看