Link.
Description.
Alice Bob 打隔膜,有一棵 (n) 个点的树,最初棋子在 (1) 节点。
Alice 删掉一个节点,然后 Bob 移动棋子到一个没到过的地方。
Alice 不知道 Bob 的每次操作
问 Alice 有无必胜策略
(nle 400)
Solution.
首先发现 (k) 增加时无解情况要求的叶子增加叶子深度也增加。
构造一个无解情况,就需要 (k) 条深度为 (k) 的链,点数是 (k^2) 级别的。
所以如果 (k^2ge n),那肯定有解了。
所以 (k) 的范围变成了 (20)。
每次贪心策略肯定是第 (i) 轮删掉一个深度为 (i) 的点(根为 (0)),这样肯定最优。
因为 Bob 操作不确定,所以我们肯定要把所有深度为 (K) 的点删完。
然后可以考虑 dfn dp,就把 dfn 拉出来,然后直接跑状压 dp。
状压 dp 记录当前选了深度为多少的点,直接转移就行了。
Coding.
点击查看代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=405;struct ${int d,w;};vector<$>v[N];
struct edge{int to,nxt;}e[N<<1];int n,K,et,head[N],lim;
int dep[N],lf[N],rg[N],dt;char dp[N][524289],vs[N];
inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
inline void dfs(int x,int fa)
{
vs[x]=1,lf[x]=dt;if((dep[x]=dep[fa]+1)==K) return rg[x]=++dt,void();
for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) dfs(e[i].to,x);
rg[x]=dt;
}
int main()
{
read(n,K);for(int i=1,x,y;i<n;i++) read(x,y),adde(x,y),adde(y,x);
if(K*K>=n) return puts("DA"),0;else dep[0]=-1,dfs(1,0),dp[0][0]=1,lim=(1<<K)-1;
for(int i=1;i<=n;i++) if(vs[i]&&i!=1) v[lf[i]].push_back(($){dep[i]-1,rg[i]});
//for(int i=0;i<=n;i++) for($ j:v[i]) printf("%d %d : %d
",i,j.w,j.d);
for(int i=0;i<dt;i++) for(int j=0;j<=lim;j++) if(dp[i][j])
for(auto x:v[i]) if(!((j>>x.d)&1)) dp[x.w][j|1<<x.d]=1;
char rs=0;for(int i=0;i<=lim;i++) rs|=dp[dt][i];
return puts(rs?"DA":"NE"),0;
}