1. 程式人生 > 其它 >揹包問題 DP

揹包問題 DP

各種各樣的基礎揹包

\(0-1\) 揹包

非常樸素,複雜度 \(O(nV)\)

void z_o_pack(int c,int v)
{
	 for(int i=V;i>=c;i--)
	 	 dp[i]=max(dp[i],dp[i-c]+v);
}

完全揹包

複雜度 \(O(nV)\)

void comp_pack(int c,int v)
{
	 for(int i=c;i<=V;i++)
	 	 dp[i]=max(dp[i],dp[i-c]+v);
}

多重揹包

這裡的寫的是單調佇列優化的多重揹包。

複雜度可以達到 \(nV\)

int ql,qr;
struct QUE
{
	 int num,val;
}que[Maxv];
void many_pack(int c,int w,int m)
{
	 if(!c) { add+=m*w; return; }
	 m=min(m,V/c);
	 for(int pos=0,s;pos<c;pos++)
	 {
	 	 ql=1,qr=0,s=(V-pos)/c;
	 	 for(int j=0;j<=s;j++)
	 	 {
	 	 	 while(ql<=qr && que[qr].val<=(dp[pos+j*c]-j*w)) qr--;
	 	 	 que[++qr]=(QUE){j,dp[pos+j*c]-j*w};
	 	 	 while(ql<=qr && (j-que[ql].num)>m) ql++;
	 	 	 dp[pos+j*c]=max(dp[pos+j*c],que[ql].val+j*w);
		 }
	 }
}

樹形依賴揹包

複雜度:\(O(n^2)\)

雖然有三層迴圈,但是內層運算總量與整棵子樹內點對個數一致。

void dfs(int x)
{
	 siz[x]=1,dp[x][1]=w[x];
	 for(int i=hea[x];i;i=nex[i])
	 {
	 	 dfs(ver[i]);
	 	 siz[x]+=siz[ver[i]];
	 	 for(int j=min(siz[x],V+1);j>=2;j--)
	 	 	 for(int k=1;j-k>=1;k++)
	 	 	 	 dp[x][j]=max(dp[x][j],dp[ver[i]][k]+dp[x][j-k]);
	 }
}

常見例題:

P1941 飛揚的小鳥

P1941 solution