Codeforces Round #407 (Div. 2)-E-The Great Mixing-滚动数组或者dfs

给定一种浓度的啤酒,给你个数字n,下面是n种浓度的啤酒,让你配成这种浓度的啤酒,问你最少需要多少份原料啤酒。
因为浓度范围很大,1后面6个零,背包就算了。范围太大。
方法1 用bitset实现滚动数组,然后用位运算可以完全模拟配酒的过程(关键在那个或),并且位运算很快,不会超时。
方法2 用BFS,要注意用map来记录他们出现的次数,这个和第一种思路差不多,就是实现方法不太一样,还有就是需要用一个map,
两种写法有异曲同工之妙。
注意充分理解或运算(上一种状态包含所有配酒的一杯的状态,下一状态,加一杯,所有的上一种状态都加上这一个,得到aa,ba,ca,da,并且在这个i中再进行或运算的时候不会丢失,在保留上述四种前提下得到 ab,bb,cb,db,如果撞了只会得到一个,)

#include <bits/stdc++.h>
using namespace std;
int main()
{  int m,n;
   int a[10000006];
   queue<int>q;
   while(!q.empty())
    q.pop();
   map<int ,int >mp;
    scanf("%d%d",&m,&n);

   for(int i=0;i<n;i++)
    {scanf("%d",&a[i]);
     a[i]-=m;
    }
   sort(a,a+n);
    int cnt=unique(a,a+n)-a;//去重。
   q.push(0);
    while(!q.empty())
    {   int u=q.front();
        q.pop();
        for(int i=0;i<cnt;i++)
        {   int y=u+a[i];
           if(abs(y)>=1001)
             continue;//超量就继续,不用在判断了。
           if(y==0)
           {   cout<<mp[u]+1<<endl;
              return 0;
           }
            if(!mp[y])//保证他是第一次出现,才加上。不然重复的数太多。
            {
                mp[y]=mp[u]+1;
               q.push(y);

            }

        }

    }
    cout<<"-1"<<endl;




    return 0;
}
#include <bits/stdc++.h>
//前几天我误以为我理解了这个代码,后来发现还是没有理解bitset的精髓。
/*bitset竟然完美的代替了背包,当l为1是,
//他的每一个置1的地方就是一个试剂的容量
而当l等于2的时候,会得到各种试剂的两种的配料,自己想想,
关键是滚动数组的搞,太会玩了,城里人就是强。


*/
  using namespace std;
  const int maxn=1e6+10;
  int n,k;
  int a[maxn];
  bitset<2010> dp[2];
  int main()
  {
     //freopen("de.txt","r",stdin);
     scanf("%d%d",&k,&n);
          for(int i=0;i<n;i++)
            {scanf("%d",&a[i]);
             a[i]-=k;
            }
            sort(a,a+n);
           n=unique(a,a+n)-a;//得到的是位置。
           int t=1;
           memset(dp,0,sizeof(dp));
           dp[1-t][1000]=1;
           for(int i=1;i<=1020;i++)
           {   for(int j=0;j<n;j++)
                {  if(a[j]>0)
                     dp[t]|=dp[1-t]<<(a[j]);
                    else
                      dp[t]|=dp[1-t]>>(-a[j]);
                }
               if(dp[t][1000]!=0)
               {  cout<<i<<endl;
                  return 0;

               }
               t=1-t;
               dp[t].reset();

           }
       printf("-1\n");





     return 0;
 }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值