题目:带领m个士兵,存在n个房间(n-1条通路,1号房间为起点);每个房间有两个参数:bugs数以及价值。
每个士兵可以抵抗20个bugs,参与抵抗的士兵不继续往下走,只有消灭房间中的所有bugs,才可以得到该房间的价值。
要到达下一个房间,必须先将当前房间的bugs全部消除;并且走过的房间就不再到达。
问有m个士兵的情况下,怎样使最后得到的价值最大,最大为多少?
f(i, j) = max { max{ f(i, j-k) + f(v, k) | 1<=k<=j-cost(i) } | v是i的儿子节点 }
#include <bits/stdc++.h>
using namespace std;
const int maxn=110;
int n,m,val[maxn],w[maxn];
vector<int>a[maxn];
int dp[maxn][maxn];
void dfs(int u,int fa)
{
if(!w[u]&&a[u].size()==1&&u!=1)//是叶子节点但是没有bug,依然需要士兵过去!
w[u]++;
for(int i=w[u];i<=m;i++)
dp[u][i]=val[u];
for(int i=0;i<a[u].size();i++)
{
int v=a[u][i];
if(v==fa) continue;
dfs(v,u);
for(int j=m;j>=w[u];j--)///背包过程
for(int k=1;k<=j-w[u];k++)
{
dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);///方程
}
}
}
int main()
{
///freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m),n!=-1&&m!=-1)
{
for(int i=1;i<=n;i++)
{
int tmp;
scanf("%d%d",&tmp,&val[i]);
w[i]=tmp/20;
if(tmp%20) w[i]++;///多出来的bugs
}
for(int i=1;i<=n;i++)
a[i].clear();
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
}
memset(dp,0,sizeof dp);
if(m==0)//判断没有士兵哪个节点也去不了
{
puts("0");
continue;
}
dfs(1,-1);
printf("%d\n",dp[1][m]);
}
return 0;
}
写的另一个版本的dp方程思路略有不同,代码比较繁琐
#include <bits/stdc++.h>
using namespace std;
const int maxn=110;
int n,m,val[maxn],w[maxn];
vector<int>a[maxn];
int tmp[maxn],dp[maxn][maxn];
void dfs(int u,int fa)
{
if(!w[u]&&a[u].size()==1&&u!=1)///
w[u]++;
for(int i=0;i<a[u].size();i++)
{
int v=a[u][i];
if(v==fa) continue;
dfs(v,u);
memset(tmp,0,sizeof tmp);//暂时存已经入选的子节点的最有情况
for(int j=0;j<=m;j++)
for(int k=0;k<=(m-j);k++)
{
int t1=dp[u][j],t2=dp[v][k];
if(!j) t1=0;////判断不为0是因为子节点那也必须得有士兵过去
if(!k) t2=0;////判断不为0是因为子节点那也必须得有士兵过去
tmp[j+k]=max(tmp[j+k],t1+t2);
}
for(int j=0;j<=m;j++)
dp[u][j]=tmp[j];///暂时存已经入选的子节点的最有情况
}
for(int j=m;j>=w[u];j--)
dp[u][j]=dp[u][j-w[u]]+val[u];///再把自身需要的w[u]处理一下
for(int j=0;j<w[u];j++)
dp[u][j]=0;
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m),n!=-1&&m!=-1)
{
for(int i=1;i<=n;i++)
{
int tmp;
scanf("%d%d",&tmp,&val[i]);
w[i]=tmp/20;
if(tmp%20) w[i]++;///
}
for(int i=1;i<=n;i++)
a[i].clear();
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
}
memset(dp,0,sizeof dp);
if(m==0)///
{
puts("0");
continue;
}
dfs(1,-1);
printf("%d\n",dp[1][m]);
}
return 0;
}