[BZOJ]4813: [Cqoi2017]小Q的棋盘
Time Limit: 10 Sec Memory Limit: 512 MB
Description
小Q正在设计一种棋类游戏。在小Q设计的游戏中,棋子可以放在棋盘上的格点中。某些格点之间有连线,棋子只能在有连线的格点之间移动。整个棋盘上共有V个格点,编号为0,1,2…,V-1,它们是连通的,也就是说棋子从任意格点出发,总能到达所有的格点。小Q在设计棋盘时,还保证棋子从一个格点移动到另外任一格点的路径是唯一的。
小Q现在想知道,当棋子从格点0出发,移动N步最多能经过多少格点。格点可以重复经过多次,但不重复计数。
Input
第一行包含2个正整数V,N,其中V表示格点总数,N表示移动步数。
接下来V-1行,每行两个数Ai,Bi,表示编号为Ai,Bi的两个格点之间有连线。
V,N≤ 100, 0 ≤Ai,Bi<V
Output
输出一行一个整数,表示最多经过的格点数量。
Sample Input
5 2
1 0
2 1
3 2
4 3
1 0
2 1
3 2
4 3
Sample Output
3
从格点 0 出发移动 2 步。经过 0, 1, 2 这 3 个格点。
从格点 0 出发移动 2 步。经过 0, 1, 2 这 3 个格点。
Solution
树形DP,f[i][j][0/1]表示走到点i,再往子树内走至多j步,回/不回到这个点最多遍历多少个点,随便转移下呗,复杂度$O(n^3)$。
Code
#include<cstdio> #include<algorithm> using namespace std; inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0'; return x; } #define MN 100 struct edge{int nx,t;}e[MN*2+5]; int k,h[MN+5],en,f[MN+5][MN+5][2]; inline void ins(int x,int y) { e[++en]=(edge){h[x],y};h[x]=en; e[++en]=(edge){h[y],x};h[y]=en; } void dp(int x,int fa) { int i,j,l; for(i=0;i<=k;++i)f[x][i][0]=f[x][i][1]=1; for(i=h[x];i;i=e[i].nx)if(e[i].t!=fa) { dp(e[i].t,x); for(j=k;j;--j)for(l=0;l<j;++l) { if(j+1>l)f[x][j][0]=max(f[x][j][0],f[x][j-2-l][0]+f[e[i].t][l][0]); f[x][j][1]=max(f[x][j][1],f[x][j-2-l][1]+f[e[i].t][l][0]); f[x][j][1]=max(f[x][j][1],f[x][j-1-l][0]+f[e[i].t][l][1]); } } } int main() { int n,i; n=read();k=read(); for(i=1;i<n;++i)ins(read(),read()); dp(0,0); printf("%d",f[0][k][1]); }