POJ 1155ios
題意:電視臺發送信號給不少用戶,每一個用戶有願意出的錢,電視臺通過的路線都有必定費用,求電視臺不損失的狀況下最多給多少用戶發送信號。app
要知道用戶都在葉子節點,費用消耗在使用選擇的路徑上,每條路徑的使用費用給出,每一個用戶支付的費用給出。ide
輸入:N爲總節點數,M爲用戶數,1爲電視臺, 2 to N-M 是中轉站,N-M+1到N是潛在用戶spa
對於1到N-M的中繼點,給出鏈接的點的個數K,K對(A,C)表示鏈接到A點,這條路徑的費用是C3d
最後是M個整數,表示用戶支付的費用code
分析:blog
int num[maxn];//記錄每一個節點下面的總用戶數 int dp[maxn][maxn];//i:i的子樹中,j:節點下面的使用用戶數,能達到的最大的剩餘利潤 //dp:最大剩餘利潤:線路費用-使用用戶支付的費用
至關於樹形揹包:
dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-len[u][i]);
temp[j]表示原來的dp[u][j]
對於搜索出來的一棵樹,對於它的孩子,能夠選擇加仍是不加,其中len[u][i]剛好表示u到當前選擇的v的代價
完整寫法:
for(int j=0;j<=num[u];j++){ temp[j]=dp[u][j]; } for(int j=0;j<=num[u];j++){ for(int k=1;k<=num[v];k++){//注意k!=0,不然多減小了i dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-len[u][i]); } } num[u]+=num[v];
代碼:get
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <vector> 5 #define maxn 3100 6 #define INF 99999999 7 using namespace std; 8 9 int num[maxn];//記錄每一個節點下面的總用戶數 10 int dp[maxn][maxn];//i:處理的節點數,j:節點下面的使用用戶數 11 //dp:最大剩餘利潤:線路費用-使用用戶支付的費用 12 int N,M; 13 vector<int>G[maxn]; 14 vector<int>len[maxn]; 15 int temp[maxn]; 16 void dfs(int u,int fa){ 17 18 // cout<<"u="<<u<<endl; 19 // for(int i=0;i<G[u].size();i++){ 20 // int v=G[u][i]; 21 // if (v==fa) continue; 22 // dfs(v); 23 // num[u]+=num[v]; 24 // } 25 // //用子節點更新u 26 // int sum=0; 27 // for(int i=0;i<G[u].size();i++){//依次枚舉下層節點 28 // int v=G[u][i]; 29 // if (v==fa) continue; 30 // for(int j=0;j<=sum;j++){//設置這個的緣由是,仔細看下面,本來的dp[u][j]已經被覆蓋了 31 // temp[j]=dp[u][j]; 32 // } 33 // for(int j=0;j<=sum;j++){ 34 // for(int k=0;k<=num[v];k++){ 35 // dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-len[u][i]); 36 // } 37 // } 38 // sum+=num[v]; 39 // } 40 //咱們能夠看出,上面兩部分能夠和在一塊兒寫,並且每次更新的num[u]就是sum 41 42 dp[u][0]=0; 43 for(int i=0;i<G[u].size();i++){ 44 int v=G[u][i]; 45 if (v==fa) continue; 46 dfs(v,u); 47 for(int j=0;j<=num[u];j++){ 48 temp[j]=dp[u][j]; 49 } 50 for(int j=0;j<=num[u];j++){ 51 for(int k=1;k<=num[v];k++){//注意k!=0,不然多減小了i 52 dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-len[u][i]); 53 } 54 } 55 num[u]+=num[v]; 56 } 57 return ; 58 } 59 void solve(){ 60 for(int i=M;i>=0;i--){ 61 if (dp[1][i]>=0) { 62 printf("%d\n",i); 63 break; 64 } 65 } 66 return ; 67 } 68 int main(){ 69 while(~scanf("%d%d",&N,&M)){ 70 for(int i=0;i<=N;i++) G[i].clear(); 71 for(int i=1;i<=N-M;i++){ 72 int k; 73 scanf("%d",&k); 74 for(int j=1;j<=k;j++){ 75 int v,c; 76 scanf("%d%d",&v,&c); 77 G[i].push_back(v); 78 len[i].push_back(c); 79 } 80 } 81 memset(num,0,sizeof(num)); 82 for(int i=0;i<=N;i++){ 83 for(int j=0;j<=N;j++) dp[i][j]=-INF; 84 } 85 for(int i=N-M+1;i<=N;i++){ 86 scanf("%d",&dp[i][1]); 87 num[i]=1; 88 } 89 dfs(1,-1); 90 solve(); 91 } 92 return 0; 93 }
POJ 2486string
題意:Wshxzt從根節點1開始在蘋果樹上游歷,樹上的每一個節點都會存在apple[i]個蘋果,從一個節點到它的鄰節點耗費步數1。如今Wshxzt能夠步行step步,求她能夠獲得的最大蘋果數量。it
輸入:N節點數,K最大步數,每一個節點的蘋果數,N-1條邊
分析:
代碼:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<vector> 5 #define MAXN 110 6 #define MAXK 220 7 using namespace std; 8 9 vector<int>G[MAXN]; 10 int anum[MAXN]; 11 int dp[MAXN][MAXK][2]; 12 int N,K; 13 int temp[MAXN]; 14 void dfs(int u,int fa){ 15 dp[u][0][1]=anum[u]; 16 dp[u][0][0]=anum[u]; 17 for(int i=0;i<G[u].size();i++){ 18 int v=G[u][i]; 19 if (v==fa) { 20 continue; 21 } 22 dfs(v,u); 23 for(int j=K;j>=0;j--){ 24 for(int t=1;t<=j;t++){ 25 dp[u][j][0]=max(dp[u][j][0],dp[v][t-1][0]+dp[u][j-t][1]); 26 if (t==1) continue; 27 dp[u][j][0]=max(dp[u][j][0],dp[v][t-2][1]+dp[u][j-t][0]); 28 dp[u][j][1]=max(dp[u][j][1],dp[v][t-2][1]+dp[u][j-t][1]); 29 } 30 } 31 } 32 33 return ; 34 } 35 int main(){ 36 while(~scanf("%d%d",&N,&K)){ 37 for(int i=1;i<=N;i++){ 38 scanf("%d",&anum[i]); 39 } 40 for(int i=0;i<=N;i++) G[i].clear(); 41 for(int i=1;i<=N-1;i++){ 42 int u,v; 43 scanf("%d%d",&u,&v); 44 G[u].push_back(v); 45 G[v].push_back(u); 46 } 47 memset(dp,0,sizeof(dp)); 48 for(int i=0;i<=N;i++){ 49 for(int j=0;j<=K;j++) dp[i][j][0]=dp[i][j][1]=anum[i]; 50 } 51 dfs(1,-1); 52 printf("%d\n",dp[1][K][0]); 53 } 54 return 0; 55 }