1. 程式人生 > >【題解】洛谷P1064[NOIP2006]金明的預算方案 有依賴的揹包問題

【題解】洛谷P1064[NOIP2006]金明的預算方案 有依賴的揹包問題

題目連結 在這裡插入圖片描述 在這裡插入圖片描述

我們把附件和它的主件歸到一組,其中主件為每組第一項編號為0。因為每組最多兩個附件,對於每一組,決策有以下五種(假定存在兩個附件): 1.不取這組 2.只取主件 3.取主件和附件1 4.取主件和附件2 5.取主件和附件1附件2 設 F[i,j]F[i,j] 表示考慮到第 ii 組容量為 jj 時的最大價值 狀態轉移方程(假定存在兩個附件) F[i,j]=max{F[i1,j]F[i1,jv[i][0]]+v[i][0]×p[i][0]F[i1,jv[i][0]v[i][1]]+v[i][0]×p[i][0]+v[i][1]×p[i][1]F[i1,jv[i][

0]v[i][2]]+v[i][0]×p[i][0]+v[i][2]×p[i][2]F[i1,jv[i][0]v[i][1]v[i][2]]+v[i][0]×p[i][0]+v[i][1]×p[i][1]+v[i][2]×p[i][2]F[i,j]=\max\begin{cases}F[i-1,j]\\F[i-1,j-v[i][0]]+v[i][0]\times p[i][0]\\F[i-1,j-v[i][0]-v[i][1]]+v[i][0]\times p[i][0]+v[i][1]\times p[i][1]\\F[i-1,j-v[i][0]-v[i][2]]+v[i][0]\times p[i][0]+v[i][2]\times p[i][2]\\F[i-1,j-v[i][0]-v[i][1]-v[i][2]]+v[i][0]\times p[i][0]+v[i][1]\times p[i][1]+v[i][2]\times p[i][2]\end{cases}

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n,m,v[61],p[61],w[61],tot,q[61],gro[61],f[32001];
vector<int>g[61];
int main()
{
	//freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    	scanf("%d%d%d",&v[i],&p[i],&q[i]),w[i]=v[i]*p[i];
    for(int i=1;i<=m;i++)
        if(q[i]==0)g[++tot].push_back(i),gro[i]=tot;
    for(int i=1;i<=m;i++)
        if(q[i]>0)g[gro[q[i]]].push_back(i);
    for(int i=1;i<=tot;i++)
    	for(int j=n;j>=0;j--)
    	{
    		if(j>=v[g[i][0]])f[j]=max(f[j],f[j-v[g[i][0]]]+w[g[i][0]]);
    		if(g[i].size()>=2&&j>=v[g[i][0]]+v[g[i][1]])f[j]=max(f[j],f[j-v[g[i][0]]-v[g[i][1]]]+w[g[i][0]]+w[g[i][1]]);
    		if(g[i].size()>=3)
    		{
    			if(j>=v[g[i][0]]+v[g[i][1]]+v[g[i][2]])f[j]=max(f[j],f[j-v[g[i][0]]-v[g[i][1]]-v[g[i][2]]]+w[g[i][0]]+w[g[i][1]]+w[g[i][2]]);
    			if(j>=v[g[i][0]]+v[g[i][2]])f[j]=max(f[j],f[j-v[g[i][0]]-v[g[i][2]]]+w[g[i][0]]+w[g[i][2]]);
			}
		}
	printf("%d\n",f[n]);
    return 0;
}

總結

一道典型的有依賴的揹包問題,要學會如何處理這類問題。