(男人八题)多重背包 POJ 1743 Coins

来源:互联网 发布:手机扒谱软件 编辑:程序博客网 时间:2024/06/06 15:53
Coins
Time Limit: 3000MSMemory Limit: 30000KTotal Submissions: 25919Accepted: 8768

Description

People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar.One day Tony opened his money-box and found there were some coins.He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch. 
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

The input contains several test cases. The first line of each test case contains two integers n(1<=n<=100),m(m<=100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000). The last test case is followed by two zeros.

Output

For each test case output the answer on a single line.

Sample Input

3 101 2 4 2 1 12 51 4 2 10 0

Sample Output

84

Source

LouTiancheng@POJ


题意:给一系列物品,每种物品价值为A,数量为C ,给定一个m , 问用这些物品组合得出的价值在m内的有多少种
思路:
我用的是二进制多重背包,一开始果断超时......  然后我只能想到各种常数优化......一开始的时候价值为0,然后开始扩展可能的价值,这里有点像bfs吧....然后搜出m/2种可能的组合之后,我们就不用这种方法搜了,我们开始反着来看,我们考虑还没组合出的价值,把剩下没组合过的容量,分出来再一个个考虑,最理想的当然是确认一个容量是可能的之后,就直接把他删掉,一直操作到物品用完了,然后剩下还没能组合出来的,就是不能组合出的容量,由于我不知道有什么办法能常数时间内删掉一个元素,(我想用链表的,但是好像更慢),于是这里我就用了lazy的思想,当标记的组合达到剩下的没能组合出的容量个数的一半时,才开始把还没组合出的容量再一次分出来,继续以上操作。
反正想法略搓,将就下吧。。。

代码:
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<string>
#include<deque>
#include<queue>
#include<math.h>
#include<vector>
#include<map>
#include<stack>
#include<set>
#include<list>
using namespace std;
const int MAX = 100000+10;
#define MOD 99997
const int inf = 0xffffff;
bool dp[MAX];
int cur[MAX];
int rest[MAX];
int sz;
int num;
int A[MAX];
int w[MAX];
int n,m;

void MulPack(int amount,int C)
{
int k = 1;
while (k<amount)
{
w[num++] = k*C;
amount -= k;
k *= 2;
}
w[num++] = amount*C;
}

int main()
{
while (scanf("%d%d",&n,&m) , n || m)
{
for (int i = 0 ; i < n ; ++i)
scanf("%d",A+i);
memset(dp,0,sizeof(dp));
sz = num = 0;
cur[sz++] = 0;
dp[0] = true;
for (int i = 0 ; i < n ; ++i)
{
int k;
scanf("%d",&k);
MulPack(k,A[i]);
}
int j = 0;
while ( j < num)
{
int tem_sz = sz;
for (int i = 0 ; i < tem_sz ; ++i) if (cur[i]+w[j]<=m && !dp[cur[i]+w[j]])
{
cur[sz++] = cur[i]+w[j];
dp[cur[i]+w[j]] = true;
}
++j;
if (sz>=m/2) break;
}
int rest = m-sz;
sz = 0;
for (int i = 1 ; i <= m ; ++i) if (!dp[i])
cur[sz++] = i;
int sign = 0;
while ( j < num)
{
if (sign>=rest/2)
{
int tem_sz = sz;
sz = 0;
for (int i = 0 ; i < tem_sz ; ++i) if (!dp[cur[i]])
cur[sz++] = cur[i];
rest -= sign;
sign = 0;
}
for (int i = sz-1 ; i >= 0 ; --i) if (!dp[cur[i]])
{
if (cur[i]-w[j]>=0 && dp[cur[i]-w[j]])
{
dp[cur[i]] = true;
++sign;
}
}
++j;
}
int cnt = 0;
for (int i = 1 ; i <= m ; ++i) if (dp[i])
++cnt;
printf("%d\n",cnt);
}
}
0 0
原创粉丝点击