算法設計與分析 3.2 小綿羊


★題目描述

本期活動中,共有N件商品參與促銷。顧客可以直接選擇M件拿走。

但是,拿走商品有一定的限制,某些商品不能被直接拿走,如果想要拿走他,必須要先拿走他指定的另一件特定商品。

請你計算一下,最多能夠拿走總價值為多少的商品。

★輸入格式

第一行包括兩個正整數N, M,表示共有N件商品,你可以拿走M件。

接下來的N行,每i行包括兩個自然數Ai,Bi。

若A = 0, 則表示該商品能直接拿走,若A != 0,則代表你需要先拿走第A個商品。

Bi代表該商品的價值。商品編號從1開始。

輸入保證商品之間不會出現環。

★輸出格式

輸出僅包括一個正整數,表示你能拿走的最大總價值。

★樣例輸入

3 2
0 1
0 2
0 3

★樣例輸出

5

★提示

對於100%的數據,1<=N,M<=300,0<=Bi<=1e6.

/*
先虛構出0節點,那么這就是一個完整的樹。
約束是只有得到父節點,才能得到子節點。
參考依賴背包的做法,使用鄰接表保存這棵樹
但是本題中沒有背包容量約束,只是限定取個數,因此每次都取價值最大的商品
動態規划使用 F[父節點][個數]:在購買了當前父節點情況下,再買m-1個子節點商品所能得到的最大價值
里對於樹中的每個節點來說,就是一個分組背包問題。每個子節點是一組物品。 
我們從葉子節點往上到根節點規划,當規划到 0 節點時,F[0][m]即為我們所求 
	
鄰接表
	假設有一棵樹如下: 
		    0 
		1   2   3
 	  4 5	6  7 8

	用鄰接表可以寫成
	 H   NE
	 0   3 2 1 -1
	 1   5 4 -1
	 2   6 -1
	 3   8 7 -1
	 4   -1
*/ 
#include<bits/stdc++.h> 
using namespace std;
int N,M; //物品件數,每人限購個數 
int H[301], NE[301]; //用鄰接表保存樹結構,H保存鄰接表的頭,NE是有共同起點下的另一條邊 
int W[301]; //物品的價值 
int F[301][301]; //前一維存放父節點、后一維存放每人限購件數 


void dfs(int p){
	for(int i=H[p]; i!=-1; i=NE[i]){ //p是父節點商品序號,所有i都是其子節點商品序號 
		dfs(i);
		for(int m=M; m>=1; --m){//因為要留出一個買父節點p的物品,所以只能分配出2~m個給子節點商品 
			for(int m2=0; m2<=m; ++m2){ //接着再分,每個子節點能得到的分配到的個數是m2 
				F[p][m]=max(F[p][m], F[p][m-m2]+F[i][m2]);
			}
		} 
	}
    for(int m=M; m>=1; --m) F[p][m] = F[p][m-1]+W[p]; //這里要加上P節點的價值哦 
} 

int main(){
	cin>>N>>M;
	
	//構建鄰接表 
	memset(H, -1, sizeof(H)); 
	int p; 
	for(int i=1; i<=N; ++i){
		scanf("%d%d",&p,&W[i]);
		NE[i]=H[p];
		H[p]=i;	
	}

	W[0]=0;//虛構0節點
	++M; //因為加上虛構節點,所以購買個數要加1 
	memset(F, 0, sizeof(F));
	dfs(0);
	
	cout<<F[0][M]<<endl;
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM