1. 程式人生 > >【動態規劃】常見揹包問題合集

【動態規劃】常見揹包問題合集

01揹包: 

有N件物品和一個容量為V的揹包。(每件物品只有一件)第i件物品的費用是c[i],價值是v[i],求解將哪些物品裝入揹包使總價值最大。

轉移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]},可以優化只用一維陣列.
程式碼如下: 
	for(int i=0;i<nPack;i++)
		for(int j=nMaxVolume;j>=w[i];j--)
			if(record[j-c[i]]+v[i]>record[j])
					record[j]=record[j-c[i]]+v[i];

完全揹包:

如果物品不計個數,即每個物品有無窮多件的話,稍微改一下程式碼即可。 

	for(int i=0;i<nPack;i++)
		for(int j=w[i];j<=nMaxVolume;j++)
			if(record[j-c[i]]+v[i]>record[j])
					record[j]=record[j-c[i]]+v[i];


多重揹包:

每個物品給出確定的件數,求可以得到的最大價值。 

	for(i=0;i<kind;i++)
		for(j=0;j<bag[i];j++)
			for(k=nManVolume;k>=v[i];k--)
				if(record[j-c[i]]+v[i]>record[j])
					record[j]=record[j-c[i]]+v[i];

優化版本:
//0-1揹包,代價為cost,獲得的價值為weight
void ZeroOnePack(int cost,int weight)
{
    for(int i=nValue;i>=cost;i--)
      dp[i]=max(dp[i],dp[i-cost]+weight);
}
//完全揹包,代價為cost,獲得的價值為weight
void CompletePack(int cost,int weight)
{
    for(int i=cost;i<=nValue;i++)
      dp[i]=max(dp[i],dp[i-cost]+weight);
}
//多重揹包
void MultiplePack(int cost,int weight,int amount)
{
    if(cost*amount>=nValue) CompletePack(cost,weight);
    else
    {
        int k=1;
        while(k<amount)
        {
            ZeroOnePack(k*cost,k*weight);
            amount-=k;
            k<<=1;
        }
        ZeroOnePack(amount*cost,amount*weight);
    }
}


混合揹包

01揹包,完全揹包,多重揹包的混合體

	for(i=0;i<n;i++)
	{
		if(第i件物品是01揹包)
			ZeroOnePack(c[i],v[i]);
		else if(第i件物品是完全揹包)
			CompletePack(c[i],v[i]);
		else if(第i件物品是多重揹包)
			MultiplePack(c[i],v[i]); 
	}


二維揹包:

對於每件物品有兩種不同費用,比如有n種物品,每種物品都有體積vi,重量wi,價值ti,限制體積最多為V,重量最多為W

增加了一維費用,只需要狀態也增加一維即可。設f[i][x][y]表示前i件物品,付出兩種代價分別為x和y時可以獲得的最大價值。

f[i][x][y]=max{f[i-1][x][y],f[i-1][x-v[i]][y-w[i]]+t[i]} 

	for(i=0;i<n;i++)
	{
		for(int x=V;x>=v[i];x--)
		{
			for(int y=W;y>=w[i];y--)
			{
				f[x][y]=max(f[x-v[i]][y-w[i]]+t[i],f[x][y]);	
			}	
		}	
	}


分組揹包:
有N件物品和一個容量為V的揹包。第i件物品的費用是c[i],價值是w[i]。這些物品被劃分為若干組,每組中的物品互相沖突,
最多選一件。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。
for(int i=1;i<=n;i++)//有n組 
    for(int j=V;j>=1;j--)//從後往前遍歷 
        for(int k=1;k<=m;k++)//第i組內的各個資料
            if(j-k>=0&&dp[j]<dp[j-cost[i][k]]+value[i][k])dp[j]=dp[j-cost[i][k]]+value[i][k];//cost[i][j]表示第i組第j個物品的花費,value[i][j]表示第i組第j個物品的價值 


需要注意的細節:

如果沒有要求揹包一定要裝滿,則record[i]初始化為0。如果要求一定要裝滿,則除了record[0]為0之外其他record[i]初始化為-INF。