1 条题解
-
0
设f[i][j]表示以i为根的子树保留j个节点所去掉的最少边数。初始化f[u][1]=c[u]。c[u]是这个节点的度。转移方程f[u][j]=min(f[u][j],f[u][k]+f[v][j−k]−2)。为什么要减2?这是因为我们在初始化的时候已经把连接父节点和子节点的这条边去掉了。这时候再把他们连起来,为防止重复计算,我们分别把u−>v和v−>u的边去掉(代码中是双向连边)。
#include<bits/stdc++.h> using namespace std; int c[155],n,p,f[155][205],ans=0x3f3f3f3f; struct node { int next,to; }edge[50005]; int head[50005],cnt; inline void add(int from,int to) { edge[++cnt].next=head[from]; edge[cnt].to=to; head[from]=cnt; } inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } void dfs(int now,int fa) { f[now][1]=c[now]; for (int i=head[now];i;i=edge[i].next) { int to=edge[i].to; if (to!=fa) { dfs(to,now); for (int j=p;j>=1;j--) for (int k=1;k<j;k++) f[now][j]=min(f[now][j],f[now][k]+f[to][j-k]-2); } } } int main() { memset(f,0x3f,sizeof(f)); n=read(),p=read(); for (int i=1;i<n;i++) { int x=read(),y=read(); c[x]++;c[y]++; add(x,y);add(y,x); } dfs(1,0); for (int i=1;i<=n;i++) ans=min(ans,f[i][p]); printf("%d",ans); return 0; }
- 1
信息
- ID
- 948
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者