题意:给你一颗带有权值的树,接着一个有能量的机器人,每经过一个边就要消耗对应权值的能量,求你x点能量最大能经过你几个结点
题解:我们可以dp出我 走i个点消耗最小的能量,因为我只有两种情况要么从另外一颗子树经过 j个结点然后走回来或者从另外一颗子树走j个结点不会来,所以我们要记录一些该节点走j个结点回来的最小值和不回来的最小值,接着可得转移方程就是
dp[u][i].fi = min(dp[u][i-j].fi+dp[v][j].se+2*w,min(dp[u][i].fi,dp[v][j].fi+dp[u][i-j].se+w));
dp[u][i].se = min(dp[u][i].se,dp[v][j].se+dp[u][i-j].se+2*w);
fi表示不走回来使用最少能量,se表示走回来使用最小能量,接着我们可以用0-1背包的思想先把i从后往前更新确保前面的更新不会影响后面的更新接着最后因为结点最大只有500,查询只有1W,二分暴力查询都可以
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<cstdlib>
#include<ctime>
#include<stack>
using namespace std;
#define mes(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(i = a; i <= b; i++)
#define dec(i,a,b) for(i = b; i >= a; i--)
#define fi first
#define se second
#define ls rt<<1
#define rs rt<<1|1
#define mid (L+R)/2
#define lson ls,L,mid
#define rson rs,mid+1,R
typedef double db;
typedef long long int ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
const int mx = 1e5+5;
const int inf = 0x3f3f3f3f;
const int x_move[] = {1,-1,0,0,1,1,-1,-1};
const int y_move[] = {0,0,1,-1,1,-1,1,-1};
int n,m;
vector<pii>g[mx];
pii dp[505][505];
void dfs(int u,int fa){
for(auto it: g[u]){
int v = it.fi;
int w = it.se;
if(v!=fa){
dfs(v,u);
for(int i = n; i >= 2; i--)
for(int j = 1; j < i; j++){
dp[u][i].fi = min(dp[u][i-j].fi+dp[v][j].se+2*w,min(dp[u][i].fi,dp[v][j].fi+dp[u][i-j].se+w));
dp[u][i].se = min(dp[u][i].se,dp[v][j].se+dp[u][i-j].se+2*w);
}
}
}
}
int main(){
int t,q,ca = 1;
while(scanf("%d",&n)&&n){
memset(dp,inf,sizeof(dp));
for(int i = 0; i < n; i++){
g[i].clear();
dp[i][1].fi = 0;
dp[i][1].se = 0;
}
for(int i = 2; i <= n; i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
g[u].push_back(make_pair(v,w));
g[v].push_back(make_pair(u,w));
}
dfs(0,0);
scanf("%d",&q);
printf("Case %d:\n",ca++);
while(q--){
int x;
scanf("%d",&x);
int ans = 1;
for(int i = 1; i <= n; i++){
if(x>=dp[0][i].fi) ans = i;
//cout<<dp[0][i].fi<<endl;
}
printf("%d\n",ans);
}
}
return 0;
}