本文主要是介绍poj1742 单调队列优化多重背包,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
如题:http://poj.org/problem?id=1742
Time Limit: 3000MS | Memory Limit: 30000K | |
Total Submissions: 31258 | Accepted: 10640 |
Description
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.
Input
Output
Sample Input
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
Sample Output
8 4
Source
由这一题的M,N太大,使用二进制拆分的O(MN∑logni)直接wa,于是想起以前见过的单调队列去均摊复杂度到O(MN),就是将容量拆分成余数+k*v[i],找出单调性,入队,每次在窗口大小为n,n=min(num[i],V/v[i])里取出最大值更新。又去查了资料。终于基本搞清楚了。
这篇文章讲得很好:http://blog.csdn.net/flyinghearts/article/details/5898183,大家点进去看吧,贴上我借鉴作者部分代码后的AC代码。
还有就是一点,这一题只能用f[i]表示当前价值i能不能装出来,而使用平常的单调队列去算价值==背包容量也会超。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXV 100005
#define MAXN 105
#define max(a,b)(a>b?a:b)
bool a[MAXV];
int w[MAXN];
int num[MAXN];
bool f[MAXV];
void multipack(int V,int v,int n)
{
int i,j,k;;
if(n==1)
{
for(i=V;i>=v;i--)
f[i]=f[i]||f[i-v];
return;
}
if(n*v>=V)
{
for(i=v;i<=V;i++)
f[i]=f[i]|f[i-v];
return;
}
for(j=0;j<v;j++)
{
int sum=0;
bool *p1=a,*p2=a-1;
for(k=j;k<=V;k+=v)
{
if(p2==p1+n)
sum-=*p1++;
*++p2=f[k];
sum+=f[k];
if(sum!=0)
f[k]=1;
}
}
}
int main()
{
// freopen("C:\\1.txt","r",stdin);
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
int i;
for(i=0;i<n;i++)
scanf("%d",&w[i]);
for(i=0;i<n;i++)
scanf("%d",&num[i]);
memset(f,false,sizeof(f));
f[0]=true;
for(i=0;i<n;i++)
multipack(m,w[i],num[i]);
int res=0;
for(i=1;i<=m;i++)
if(f[i]==true)
res++;
cout<<res<<endl;
}
return 0;
}
这篇关于poj1742 单调队列优化多重背包的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!