给定一种浓度的啤酒,给你个数字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;
}