noj [1480] 懒惰的风纪委Elaine (多重背包)

http://ac.nbutoj.com/Problem/view.xhtml?id=1480

  • [1480] 懒惰的风纪委Elaine

  • 时间限制: 1000 ms 内存限制: 65535 K
  • 问题描述
  • Elaine是学园都市中的一个风纪委,每天都会接到命令对某个街道进行检查,并抓捕危险分子。她所在的风纪委支部附近有M条街道。这些街道由北到南并排均匀的分布在一条直线上,每条街道之间的距离都为1。但是众所周知,Elaine是一个很懒很懒的人(-..-说我坏话!!被我看到了!!),她不想一步一步走完所有街道,但好在她的好友Kuso为她制作了大量的传送卷轴。不过,因为Kuso的能力等级太低,他制作的卷轴有严重的缺点,他的卷则只能向南飞一段固定的距离(当然,他预先制作了很多种类的卷轴),而Elaine所在的风纪委支部却在最北边。每一次出去检查,Elain都要使用好几张卷轴。但如果是某些不能传送到的地方,Elaine只能走过去了。不过回来的话,她就可以用自带的传送系统传送到支部的传送点。

    有一天,Elaine想知道,如果她从风纪委支部出发,可以检查那些街道。她手里有N种传送卷轴(1,2,3,,,N),每个卷轴可以传送的距离为Ai,卷轴的数量为Ci。则Elaine靠那些卷轴,可以不走路而直接传送的有哪些街道?

  • 输入
  • 数据有多组输入。每一组数据的第一行有两个数:N,M(0<N<=100,0<M<=1000)。分别表示传送卷轴的种类数和街道数量。在第二行有2N个数,A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000)。数据输入以0 0结束。
  • 输出
  • 每组数据占一行,输出一个数,为Elaine可以传送到的街道总数。
  • 样例输入
  • 3 10
    1 2 4 2 1 1
    2 5
    1 4 2 1
    0 0
  • 样例输出
  • 8
    4
  • 先将多重背包转换成01背包,然后在求解01背包:
  • 任何一个正整数N  都可以分解成 N = 2^0 + 2^1 + 2^2+......+(剩下不足2^n的部分)
  • 例如:13  = 1 + 2 + 4 + 6
  • 这里是对数量进行拆分;  这样的好处可以很好的降低复杂度,从O(N*N)降到O(N*logN)
  •  1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<vector>
     5 using namespace std;
     6 
     7 int dp[1010];
     8 int a[110];
     9 vector<int> v;
    10 
    11 int main()
    12 {
    13     int n,m;
    14         while(scanf("%d%d",&n,&m)&&n&&m)
    15         {
    16 
    17             int i,j;
    18             for(i=0;i<n;i++)
    19             {
    20                 scanf("%d",&a[i]);
    21             }
    22             
    23             //多重背包转换成01背包
    24             v.clear();
    25             int t;
    26             for(i=0;i<n;i++)
    27             {
    28                 int nc;
    29                 scanf("%d",&nc);
    30                 t=1;
    31                 while(t<=nc)
    32                 {
    33                     v.push_back(t*a[i]);
    34                     nc-=t;
    35                     t=t*2;
    36                 }
    37                 if(nc>0){
    38                     v.push_back(nc*a[i]);
    39                 }
    40             }
    41             
    42             //01背包求解过程
    43             memset(dp,0,sizeof(dp));
    44             dp[0]=1;
    45             int sum=0;
    46             for(i=0;i<v.size();i++)
    47             {
    48                 for(j=sum==m?m-v[i]:sum;j>=0;j--)  //这个用到优化j=sum==m?m-v[i]:sum,这个优化是必要的,不然TLE
    49                 {
    50                     if(dp[j]!=0&&j+v[i]<=m){
    51                         dp[j+v[i]]=1;
    52                     }
    53                 }
    54                 sum+=v[i];
    55                 if(sum>m)
    56                 {
    57                     sum=m;
    58                 }
    59             }
    60             int cnt=0;
    61             for(i=1;i<=m;i++)
    62             {
    63                 if(dp[i])
    64                 {
    65                     cnt++;
    66                 }
    67             }
    68             printf("%d
    ",cnt);
    69         }
    70     return 0;
    71 }
原文地址:https://www.cnblogs.com/crazyapple/p/3202179.html