/**//* 题意:给出一棵树,求一条最长为L的路,使得所有节点到这条路的距离(选离最近的点)之和最小 N<=10^4,L<=100 树DP dp[u,L]表示以u为根的子树,最长为L的路的代价(即距离之和) 其中u为其中的一个点,以u为根的子树是指在所有节点以0为根的前提下,u的这颗子树(即只有部分点) sumD[u]表示u的子树所有点到u的距离之和 sum[u]表示u的子树的节点个数
这个dp[u,L]的维护: dp[u,L] = min{ dp[u,L], dp[u,L-1], dp[v][i-1]+sumD[u]-sumD[v]-sum[v] } v是u的一个儿子 由于dp[u,L]表示的是长度不超过L的,所以需要跟dp[u,L-1]比较
定义长度不超过L,可以使整个复杂度为O(NL) 定义长度为L的话,整个复杂度会变为O(NLL) 以上是第一次dfs得到的值,这样子得到的是以0为根的答案ans[0] 当然可以以其他点为根,这时需要第二次dfs来调整整棵树的根
ans[u] = N-sum[u] + sumD[p]-sum[u] //调整其他点到根的距离 + dp[v1,a] - sumD[v1] - sum[v1] //选择两个点来作为路径,也可以是一个点的 + dp[v2,b] - sumD[v2] - sum[v2]
用tmp[l]记录目前的 min{dp[v,l] - sumD[v] - sum[v]} 即可
*/ #include<cstring> #include<cstdio> #include<algorithm>
using namespace std;
const int MAXN = 10010; const int INF = 1000000000;
inline int min(int a,int b){return a<b?a:b;}
struct Node { int v; Node *next; };
int dp[MAXN][110]; int N,L; int sumD[MAXN],sum[MAXN]; int ans[MAXN];
Node *E[MAXN],nodes[MAXN*2],*pE;
void init() { pE=nodes; for(int i=0;i<N;i++) E[i]=0; }
void add(int a,int b) { pE->v=b; pE->next=E[a]; E[a]=pE++; }
void dfs1(int u,int p) { fill(dp[u],dp[u]+L+1,INF); sum[u]=1; sumD[u]=0; for(Node *it=E[u];it;it=it->next) { int v=it->v; if(v==p)continue; dfs1(v,u); sumD[u]+=sumD[v]+sum[v]; sum[u]+=sum[v]; } dp[u][0]=sumD[u]; for(Node *it=E[u];it;it=it->next) { int v=it->v; if(v==p)continue; for(int i=1;i<=L;i++) { dp[u][i]=min(dp[u][i],dp[v][i-1]+sumD[u]-sumD[v]-sum[v]); dp[u][i]=min(dp[u][i],dp[u][i-1]); } } }
void dfs2(int u,int p) { if(u==0)ans[u]=sumD[0]; else ans[u]=N-sum[u] + sumD[p]-sum[u];// int tmp[110];//tmp[i]表示目前长度不超过i的 dp[v][i]-sumD[v]-sum[v] 的最小值 int Min = INF; fill(tmp,tmp+L+1,INF); for(Node *it=E[u];it;it=it->next) { int v=it->v; if(v==p)continue; if(L>=2)//一条a + 一条b组成 { for(int a=0;a<=L-2;a++) //如果定义长度为L的话,这里需要再for(b=0;a+b<=L-2;b++) //而定义长度不超过L的话,那个tmp[b=L-2-a]就是这个for的最优值了 //所以复杂度降为O(NL) { int b=L-2-a; Min=min(Min,tmp[b]+dp[v][a]-sumD[v]-sum[v]); } } for(int a=0;a<=L;a++)//更新tmp[] { tmp[a]=min(tmp[a],dp[v][a]-sumD[v]-sum[v]); if(a)tmp[a]=min(tmp[a],tmp[a-1]);// tmp[i]表示最多用长度为i的 所以可以=tmp[a-1] } } Min = min(Min,tmp[L-1]);//也可以只有1条的 sumD[u]=ans[u]; ans[u]+=Min; for(Node *it=E[u];it;it=it->next) { int v=it->v; if(v==p)continue; dfs2(v,u); } } int main() { // freopen("in", "r", stdin); //freopen("out", "w", stdout);
while(scanf("%d%d",&N,&L),N||L) { if(N==1){puts("0");continue;} init(); int a,b; for(int i=1;i<N;i++) { scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs1(0,0); dfs2(0,0); printf("%d\n",*min_element(ans,ans+N)); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|