程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> hdu 2126 Buy the souvenirs(求方案數的背包)

hdu 2126 Buy the souvenirs(求方案數的背包)

編輯:C++入門知識

今天上午給學弟講背包的時候,看到背包裡面有一段關於求方案數的背包的論述。那會兒我自己也不太明白所以就沒講,結果下午就做了一道這樣的題目。

有n件物品,旅客一共有m塊大洋。第一個問題,旅客最多可以買多少件物品?請注意,這裡是多少件,不是價值最大。所以這個非常好求,將所有的物品按照價值排序,先買便宜的,再買貴的。貪心的思想。這個地方有些細節需要處理,如果所有物品的價值總和比旅客的錢少,那麼就只有一個方案,旅客可以買走所有的物品。如果旅客的錢數連第一件物品都買不起,那麼就直接輸出”Sorry,you
 can't buy anything.“。

用這種方法,我們可以求出旅客最多買多少件物品,求出之後,物品的價格就有了兩種屬性,一種是錢數,一種是件數。也就是買一件物品需要的消耗是它的價格的錢數和1件物品的份額。在背包九講中,這個叫做二維費用的背包問題。

如果是求最優方案,這個問題依舊毫無壓力。但是現在的問題是求方案總數。

我們用dp[j][k]表示花費j元買k件物品的方案數,實際上很容易我們就可以得到dp[j][k]=dp[j][k]+dp[j-a[i]][k-1]。關於這個方程有兩個需要特別解釋的地方,第一個這個是空間優化後的方程,優化後的原理參見背包九講第一講01背包,這裡不再敘述。我們需要知道的是dp[j][k]在這裡指的是dp[i-1][j][k],也就是在考慮過第i-1件物品後dp[j][k]的方案數。這個解釋了這個dp[j][k]為什麼可以直接繼承過來。第二個需要解釋的是,在dp[j][k]和dp[j-a[i]][k-1]中有沒有相同的方案,即我們有沒有冒著重復計算的風險將兩者相加。答案是沒有。因為在dp[j-a[i]][k-1]這些方案中都有第i件物品,我們說過dp[j][k]實際上是dp[i-1][j][k],其中根本沒有第i件物品的影子,所以兩者不可能有重復的方案。

實際上如果了解第k大背包的算法的話,會對解決這道題有很大幫助。

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 505
int dp[N][35];
int a[N];
int cmp(const void *a,const void *b)
{
	return *(int *)a-*(int *)b;
}
int Max(int x,int y)
{
	if(x>y)
		return x;
	else
		return y;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		int sum;
		sum=0;
		int flag;
		int i,j,k;
		for(i=1;i<=n;i++)
			scanf("%d",&a[i]);
		qsort(a+1,n,sizeof(a[0]),cmp);
		flag=0;
		for(i=1;i<=n;i++)
		{
			sum+=a[i];
			if(sum<=m)
				flag=i;
		}
		if(sum<=m)
		{
			printf("You have 1 selection(s) to buy with %d kind(s) of souvenirs.\n",n);
			continue;
		}
		else if(a[1]>m)
		{
			printf("Sorry, you can't buy anything.\n");
			continue;
		}
		memset(dp,0,sizeof(dp));
		for(i=0;i<=m;i++)
			dp[i][0]=1;
		for(i=1;i<=n;i++)
		{
			for(j=m;j>=a[i];j--)
			{
				for(k=flag;k>=1;k--)
					dp[j][k]=dp[j][k]+dp[j-a[i]][k-1];
			}
		}
		if(dp[m][flag]==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",dp[m][flag],flag);
	}
	return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved