hdoj 2126 Buy the souvenirs 【另类01背包】

题意:求最多购买的件数以及有几种方法。

一看到这题就想到了背包,因为求得是种类数,所以我们可以将件数看做价值,将价格看做重量,这就变成01背包了(dp),但是还要求有几种购买方案,那么再来一个背包(kind)。

分析:有三种情况:

1》dp[j] < dp[j-s[i]]+1

那么对于这一种情况  方案背包的状态转移方程是kind[j] = kind[j-s[i]]?kind[j-s[i]]:1;(考虑到kind[j-s[i]] ==0的时候,这时候kind[j] = 1);

证明:为什么是kind[j] = kind[j-s[i]];假设原来的dp[j-s[i]]是2,为AB, AC,那么再买一件D就变成了ABD和ACD 所以... 

2》dp[j] == dp[j-s[i]]+1

那么对于这一种情况显然 dp[j] +=
 kind[j-s[i]]?kind[j-s[i]]:1;(考虑到kind[j-s[i]] ==0的时候,这时候kind[j] += 1)

证明:dp[j] == dp[j-s[i]]+1 ,虽然两者相等,但是构成不一样(例如:dp[j] = 2 为AC AB, 但是dp[j-s[i]] 为 CD, BD(仔细想一下!!!)),所以状态转移方程就是dp[j] +=  kind[j-s[i]]?kind[j-s[i]]:1

3》 

代码:dp[j] > dp[j-s[i]]+1

对于此种情况  不用考虑交换.

#include <stdio.h>
#include <string.h>
#include <algorithm>
using std::sort;
#define M 550
int dp[M];
int kind[M];
int s[M];
int n, m;
bool cmp(int a, int b){
	return a<b;
}
void DP(){
	memset(dp, 0, sizeof(dp));
	memset(kind, 0, sizeof(kind));
	int i, j;
	for(i = 0; i < n; i ++){
		for(j = m; j >= s[i]; j --){
			if(dp[j] < dp[j-s[i]]+1){  //第一种情况
				dp[j] = dp[j-1]+1;
				if(kind[j-s[i]]) kind[j]=kind[j-s[i]];  //<span style="font-size:14px;">kind[j] = kind[j-s[i]]?kind[j-s[i]]:1</span>
				else kind[j] = 1;
			}
			else if(dp[j] == dp[j-s[i]]+1){   //第二种情况
				if(kind[j-s[i]]) kind[j] += kind[j-s[i]]; //<span style="font-size:14px;">kind[j] += kind[j-s[i]]?kind[j-s[i]]:1</span>
				else kind[j] += 1;
			}
		}
	}
}
int main(){
	int t, i, j;
	scanf("%d",&t);
	while(t --){
		scanf("%d%d", &n, &m);
		for(i = 0; i < n; i ++){
			scanf("%d", &s[i]);
		}
		int ans = 0, temp = m;
		sort(s, s+n, cmp);
		DP();
		if(dp[m] == 0){
            printf("Sorry, you can't buy anything.\n");
        }
        else
        printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n", kind[m], dp[m]);

	}
	return 0;
}

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126

时间: 2024-10-13 12:42:02

hdoj 2126 Buy the souvenirs 【另类01背包】的相关文章

hdoj 1203 I NEED A OFFER! 【另类01背包】【概率背包】

题意:... 策略:动态规划. 因为是求至少能得到一个offer的概率,那我们可以反着求,求得不到一个offer的概率,最后用1减去就好了. 代码: #include<string.h> #include<stdio.h> double dp[10010]; struct node{ int a; double b; }s[10010]; int main() { int n, m, i, j; while(scanf("%d%d", &n, &

nyoj 860 又见01背包 【另类01背包】

分析: 首先这道题不能当做普通的01背包问题,因为W <= 10^9,开不了,那么大的数组,肯定有其他的思路,观察一下我们知道价值v小的很,最大100, 那我们就可以利用这一点,拿价值 之和作为原来的质量之和, 但是有一点要注意:因为题意是要在质量不超过W的范围内,找出最大的价值,我们现在是以最大的价值求质量,那么仔细分析一下,我们就能想明白,要以某价值i的背包存放尽量小的质量,这样反过来分析一下就可以知道,较小的质量有个较大的价值序号,这样完全满足题意了, 最后还有一点,就是价值背包的每一个(

(01背包)HDU - 2126 Buy the souvenirs

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126 题意:给n个物品,和m块钱,输出最多物品个数和其方案数. 委屈:求出最多物品个数就是一个裸的01背包,但是同时求出方案数,难住了我. 想了半天,感觉可以一波dp求出来,但是又想不明白状态是怎么表示和转移的. 无奈就先写个dfs提交试一发,果断超时了. 最后无奈看了题解,只能说,01背包还是不会. 其实与其说01背包不会不如说动态规划不会,感觉好难. 感觉自己好lowbee啊.. 感觉碰到dp就

hdu 2126 Buy the souvenirs(记录总方案数的01背包)

Buy the souvenirs Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1662    Accepted Submission(s): 611 Problem Description When the winter holiday comes, a lot of people will have a trip. Genera

hdu 2126 Buy the souvenirs 买纪念品(01背包,略变形)

题意:给出一些纪念品的价格,先算出手上的钱最多能买多少种东西k,然后求手上的钱能买k种东西的方案数.也就是你想要买最多种东西,而最多种又有多少种组合可选择. 思路:01背包.显然要先算出手上的钱m最多能买多少种东西k,可以从价格最少的纪念品买起,看最多能买多少种,置为k.接下来按照常规01背包计算,需要记录下方案数和组成的物品数,看代码就会懂的. 1 #include <iostream> 2 #include <stdio.h> 3 #include <cstring>

Buy the souvenirs---hdu2126(01背包输出方案数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126 有n个物品每个物品的价格是v[i],现在有m元钱问最多买多少种物品,并求出有多少种选择方法: 如果将物品的价格看做容量,将它的件数1看做价值的话,那么用01背包就可以求的花费m钱所能买到的最大件数dp[m]. 但是题目还要求方案数,因此很容易想到再建立一个数组f[j],存储j元钱能买dp[j]个物品的方案数. 在求解01背包的过程中,要分两种情况讨论: 设当前所选的物品为i 1.   若选了物

HDU 2126 Buy the souvenirs

Buy the souvenirs Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 212664-bit integer IO format: %I64d      Java class name: Main When the winter holiday comes, a lot of people will have a trip. Generally, the

饭卡------HDOJ杭电2546(还是01背包!!!!!!)

Problem Description 电子科大本部食堂的饭卡有一种非常诡异的设计,即在购买之前推断剩余金额. 假设购买一个商品之前,卡上的剩余金额大于或等于5元,就一定能够购买成功(即使购买后卡上剩余金额为负),否则无法购买(即使金额足够).所以大家都希望尽量使卡上的剩余金额最少. 某天,食堂中有n种菜出售.每种菜可购买一次. 已知每种菜的价格以及卡上的剩余金额,问最少可使卡上的剩余金额为多少. Input 多组数据.对于每组数据: 第一行为正整数n.表示菜的数量.n<=1000. 第二行包含

hdoj 1864 最大报销额 【01背包】||【dfs】

最大报销额 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 17014    Accepted Submission(s): 4959 Problem Description 现有一笔经费可以报销一定额度的发票.允许报销的发票类型包括买图书(A类).文具(B类).差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的