就是想學會01揹包~~

據說是dp裏的東西,據說就是每樣東西只有一個,據說就是最優解嘛~~

反正最簡單直接的樣子就是:
有一個體積C爲的揹包,還有N件物品,每件物品都有相對應的體積和價值,那從中選擇物品裝入揹包,使揹包價值最大。每樣物品只有一個,放或不放。
那麼,我們設第i件物品體積爲v[i],價值爲w[i]。那我們想得到最大值的過程就是,放入一樣物品,然後比較放入這件物品後的價值  和  放入這件物品前的價值,直到這些物品都被試放過一次。
dp[i][j]=max(dp[i-1][j-v[i]]+w[i],dp[i-1][j]).
 
巨巨們說,這叫狀態轉移方程,巨巨們說的,那就理解一下它唄
對應題目理解,假設揹包體積爲10,現在有4樣物品:體積爲6 ,5,4,3;價值爲10,5,13,11.
先把 二維數組初始化爲0,i爲前幾個物品,j爲當前所分配的空間,dp[i][j]表示前幾個物品的最大價值.
放第一個物品:
從空間爲1開始,
空間爲1,就是dp[1][1],放不下,dp[1][1]=0
空間爲2,dp[1][2]=0,
同理dp[1][3]=0,dp[1][4]=0,dp[1][5]=0
當空間爲6時,可以放下,因此:
dp[1][6]=max(dp[0][0]+10 ,  dp[0][6]),顯然,前者大。dp[1][6]=10.
dp[1][7]=max(dp[0][1]+10 ,  dp[0][7]),顯然,前者大。dp[1][7]=10.
同理,
dp[1][8]=10,dp[1][9]=10,dp[1][10]=10.
 
 
  1 2 3 4 5 6 7 8 9 10
1 0 0 0 10 10 10 10 10
0  0   0  0
 

 
放第二個物品:
從空間爲1開始,
dp[2][1]=0,dp[2][2]=0,dp[2][3]=0,dp[2][4]=0,
當空間爲5時:dp[2][5]=max(dp[1][0]+5,dp[1][5])=5,
當空間爲6時:dp[2][6]=max(dp[1][0]+5,dp[1][6])=10
同理:dp[2][7]=max(dp[1][0]+5,dp[1][7])=10
    dp[2][8]=max(dp[1][0]+5,dp[1][8])=10
    dp[2][9]=max(dp[1][0]+5,dp[1][9])=10
    dp[2][10]=max(dp[1][0]+5,dp[1][10])=10
 
 
  1 2 3 4 5 6 7 8 9 10
2 0 0 0 0 5 10 10 10 10 10
1 0 0 0 0 10 10 10 10 10
0 0
放第三個物品:
從空間爲1開始,
dp[3][1]=0,dp[3][2]=0,dp[3][3]=0
dp[3][4]=max(dp[2][0]+13,dp[2][4])=13
dp[3][5]=max(dp[2][1]+13,dp[2][5])=13
dp[3][6]=max(dp[2][2]+13,dp[2][6])=13
dp[3][7]=max(dp[2][3]+13,dp[2][7])=13
dp[3][8]=max(dp[2][4]+13,dp[2][8])=13
dp[3][9]=max(dp[2][5]+13,dp[2][9])=13+5=18
dp[3][10]=max(dp[2][6]+13,dp[2][10])=13+10=23
 
 
  1 2 3 4 5 6 7 8 9 10
3 0 0 0 13 13 13 13 13 18 23
2 0 0 0 5 10 10 10 10 10
1 0 0 0 0 0 10 10 10 10 10
0 0
 
放第四個物品:
從空間爲1開始,
dp[4][1]=0,dp[4][2]=0
dp[4][3]=max(dp[3][0]+11,dp[3][3])=11
dp[4][4]=max(dp[3][1]+11,dp[3][4])=13
dp[4][5]=max(dp[3][2]+11,dp[3][5])=13
dp[4][6]=max(dp[3][3]+11,dp[3][6])=13
dp[4][7]=max(dp[3][4]+11,dp[3][7])=13+11=24
dp[4][8]=max(dp[3][5]+11,dp[3][8])=13+11=24
dp[4][9]=max(dp[3][6]+11,dp[3][9])=13+11=24
dp[4][10]=max(dp[3][7]+11,dp[3][10])=13+11=24
 
 
 
  1 2 3 4 5 6 7 8 9 10
4 0 11 13 13 13 24 24 24 24
3 0 0 13 13 13 13 13 18 13
2 0 0 0 0 5 10 10 10 10 10
1 0 0 0 0 10 10 10 10 10
0 0
emmmmm,表格是從下向上,從左向右生成
 
所以24就是最優解嘍~~~~
是時候來一發呆碼了(`・ω・´)
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
int main()
{
	int c,n,i,j;
	int v[100],w[100],dp[100][100];
	scanf("%d%d",&c,&n);
	for(i=1;i<=n;i++)
		scanf("%d",&v[i]);
	for(i=1;i<=n;i++)
		scanf("%d",&w[i]);
	memset(dp,0,sizeof(dp));
	for(i=1;i<=n;i++)
		for(j=1;j<=c;j++)
		{
			if(j>=v[i])
			{
				if((dp[i-1][j-v[i]]+w[i])>dp[i-1][j])
					dp[i][j]=dp[i-1][j-v[i]]+w[i];
				else
					dp[i][j]=dp[i-1][j];
			}
			else
					dp[i][j]=dp[i-1][j];
		} 
		printf("%d",dp[n][c]);
	return 0;
}
我以爲結束了,這時巨巨們又說話了
其實這個可以用滾動數組來存放Σ(っ°Д°;)っ,萌新第一次聽說,但巨巨們說了,那╮(╯﹏╰)╭

滾動數組,看起來就是把上面那一坨呆碼裏的二維數組換成一維數組,節約了空間!!!
但是,我們之前之所以用二維數組,原因是使每樣物品只放一次,那換成一維數組爲防止這個問題,放置時的順序在表格中就要從右向左的順序
 
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
int main()
{
	int v[100],w[100],dp[100],n,i,j;
	int c;
	scanf("%d%d",&c,&n);
	memset(dp,0,sizeof(dp)); 
		for(i=1;i<=n;i++)
			scanf("%d",&v[i]);
		for(i=1;i<=n;i++)
			scanf("%d",&w[i]);
		for(i=1;i<=n;i++)
		{
			for(j=c;j>=0;j--)
			{
				if(j>=v[i])
				{
				if(dp[j-v[i]]+w[i]>dp[j])
					dp[j]=dp[j-v[i]]+w[i];
			
				}
			}
		}
		printf("%d\n",dp[c]);
	
	return 0;
}

以上全部用的c語言,c++真的還沒學會呢╥﹏╥真的是萌新
第一次寫,如有問題,望指正!!!(´・ᴗ・`)









 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章