题意:电视台发送信号给很多用户,每个用户有愿意出的钱,电视台经过的路线都有一定费用,求电视台不损失的情况下最多给多少用户发送信号。
要知道用户都在叶子节点,费用消耗在使用选择的路径上,每条路径的使用费用给出,每个用户支付的费用给出。
输入:N为总节点数,M为用户数,1为电视台, 2 to N-M 是中转站,N-M+1到N是潜在用户
对于1到N-M的中继点,给出连接的点的个数K,K对(A,C)表示连接到A点,这条路径的费用是C
最后是M个整数,表示用户支付的费用
分析:
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];
代码:
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 ",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 }
题意:Wshxzt从根节点1开始在苹果树上游历,树上的每个节点都会存在apple[i]个苹果,从一个节点到它的邻节点耗费步数1。现在Wshxzt可以步行step步,求她可以得到的最大苹果数量。
输入: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 ",dp[1][K][0]); 53 } 54 return 0; 55 }