题意:一棵树,从上往下走m步,最多能经过多少个不同点。一个点可以重复经过。
n,m<=100.
啊,难得有这么善良的出题人。。。要是是我省的就好了( •̀ ω •́ )y
经典套路题辣,设
f[i][j],g[i][j]
表示从i走j步,不返回/返回的点数。
背包搞搞啦。
f[x][j]=max(f[x][j],f[v][k−1]+g[x][j−k])
f[x][j]=max(f[x][j],g[v][k−2]+f[x][j−k])
g[x][j]=max(g[x][j],g[v][k−2]+g[x][j−k])
注意f的不返回是不返回x,返回到v也算在f的贡献里面。
k-1,k-2分别表示的是儿子的那条边经过一次,两次。这样应该很好理解了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e3+5;
int n,m;
int a[N],b[N],c[N];
int head[N],next[N],go[N],tot;
int f[N][N],g[N][N];
inline void add(int x,int y)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
inline void dfs(int x,int fa)
{
fo(i,0,m)f[x][i]=g[x][i]=1;
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=fa)
{
dfs(v,x);
fd(j,m,0)
fo(k,1,j)
{
f[x][j]=max(f[x][j],f[v][k-1]+g[x][j-k]);
if (k>=2)
{
f[x][j]=max(f[x][j],g[v][k-2]+f[x][j-k]);
g[x][j]=max(g[x][j],g[v][k-2]+g[x][j-k]);
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
fo(i,1,n-1)
{
int x,y;
scanf("%d%d",&x,&y);x++,y++;
add(x,y);
add(y,x);
}
dfs(1,0);
printf("%d\n",max(f[1][m],g[1][m]));
}