采药

采药(jdoj1049)

    题目大意:不同于NOIP的采药,这道题的描述都是一样的,只是数据范围有毒。

    注释:总时间和药的种类全是100,000,每种药的时间和价值不大于10。

      想法:如果想NOIP那道题一样用01背包跑的话,时间复杂度是O(10^10),显然会T掉,所以,我们想拓展一下别的方法,显然,极其容易注意到每种药物的时间和价值实在是太小了,所以在处理的过程中必定会有很多药物是一模一样的,所以,想到——多重背包。但是单纯的多重背包的时间复杂度是不发生改变的,所以我们极其容易想到一种优化——二进制优化。二进制的原理是一串2的每次加上剩余的数,是一定可以凑出所有的数的,这就是二进制优化的原理。说到这儿,这题就切了......

    最后,附上丑陋的代码......

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 int a[100100];
 7 int aa[20][20];
 8 int x[100];
 9 int cnt;
10 void two(int k)//二进制优化
11 {
12     cnt=0;
13     if(k==1)
14     {
15         x[++cnt]=1;
16         return;
17     }
18     else if(k==0)
19     {
20         return;
21     }
22     else
23     {
24         k--;
25         x[++cnt]=1;
26         int now=1;
27         while(1)
28         {
29             if(k>now*2)
30             {
31                 k-=now*2;
32                 x[++cnt]=now*2;
33                 now*=2;
34             }
35             else
36             {
37                 x[++cnt]=k;
38                 return;
39             }
40         }
41     }
42 }
43 int main()
44 {
45     int n,m;
46     scanf("%d%d",&n,&m);
47     int time,val;
48     for(int i=1;i<=n;i++)
49     {
50         scanf("%d%d",&time,&val);
51         aa[time][val]++;
52     }
53     for(int i=1;i<=10;i++)
54     {
55         for(int j=1;j<=10;j++)
56         {
57             memset(x,0,sizeof(x));//important ! important !! important !!!
58             two(aa[i][j]);
59             for(int ii=1;ii<=cnt;ii++)
60             {
61                 for(int jj=m;jj>=i*x[ii];jj--)
62                 {
63                     a[jj]=max(a[jj],a[jj-i*x[ii]]+x[ii]*j);
64                 }
65             }
66         }
67     }
68     int minn=-1;
69     for(int i=m;i>=1;i--) minn=max(minn,a[i]);
70     printf("%d",minn);
71 }

 

    小结:错误

        1.清数组。

    转载请注明:http://www.cnblogs.com/ShuraK/p/7853217.html

 

转载于:https://www.cnblogs.com/ShuraK/p/7853217.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值