题意:一颗有n个节点的有根树,有Q个查询,从根节点出发,走不超过x单元距离,最多能经过多少个节点,点可重复走(n<=500,Q<=1000)
思路:
dp[u][k][flag]从u出发,经过k个点,是否回到u的距离的最小值
查询时暴力就可以
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=1010;
typedef pair<int,int> PI;
vector<PI>G[N];
int degree[N],size[N],dp[N][N][2];
void dfs(int u,int pre){
dp[u][1][0]=dp[u][1][1]=0;
size[u]=1;
for(int k=0;k<G[u].size();k++){
PI tmp=G[u][k];
if(tmp.first==pre) continue;
dfs(tmp.first,u);
size[u]+=size[tmp.first];
int v=tmp.first;
for(int i=size[u];i>=2;i--) //枚举k
for(int j=1;j<i&&j<=size[tmp.first];j++){
dp[u][i][0]=min( dp[u][i][0],min(dp[u][i-j][0]+dp[v][j][1]+2*tmp.second,dp[u][i-j][1]+dp[v][j][0]+tmp.second) );
dp[u][i][1]=min(dp[u][i-j][1]+dp[v][j][1]+2*tmp.second,dp[u][i][1]);
}
}
}
int main(){
int n,q,x,Case=1;
while(scanf("%d",&n)!=EOF){
if(n==0) break;
for(int i=1;i<=n;i++) G[i].clear();
memset(degree,0,sizeof(degree));
memset(dp,INF,sizeof(dp));
int u,v,w;
for(int i=1;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
u++,v++;
G[v].push_back(make_pair(u,w));
degree[u]++;
}
int root=0;
for(int i=1;i<=n;i++)
if(degree[i]==0) root=i;
dfs(root,0);
int q;
printf("Case %d:\n",Case++);
scanf("%d",&q);
while(q--){
scanf("%d",&x);
for(int i=n;i>=1;i--)
if(dp[root][i][0]<=x){
printf("%d\n",i);
break;
}
}
}
return 0;
}