点这里
结论题 ,图一乐
结论:如果原图中存在两个边集不交的生成树,那么 Bob \text{Bob} Bob必胜;否则 Alice \text{Alice} Alice必胜
证明有点难
首先,考虑维护两颗 不存在红边 的生成树,如果 Alice \text{Alice} Alice断掉了其中一颗树上的一条边,将这个树分成两个连通块,那么 Bob \text{Bob} Bob一定可以在另一颗树上选择一条边变成蓝色,使得这个树再次联通,最终两个生成树都只由蓝边构成
其次,如果原图中不存在这样的两颗生成树,则考虑某次 Alice \text{Alice} Alice操作时, Bob \text{Bob} Bob胜利的条件:将所有蓝色的边 复制一遍,使得存在两个边集不交的生成树。假设存在某种策略,使得 Bob \text{Bob} Bob在某次操作后满足了这个条件,那么 Alice \text{Alice} Alice可以照搬 Bob \text{Bob} Bob的策略,使得某次操作后将红边复制一遍,使得存在两个边集不交的生成树。因此 Alice \text{Alice} Alice存在可以让红边构成一颗生成树的策略。又因为原图中不存在两个边集不交的生成树,因此 Bob \text{Bob} Bob无法胜利
有点绞
发现 ( 30 9 ) \binom{30}{9} (930)比较小,直接暴搜即可。
#include
#include
#define ll long long
#define pb push_back
#define fi first
#define se second
#define db double
#define ull unsigned long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m,fa[10],fa2[10],U[30],V[30],s[30];
int find(int x){
return fa[x]==x?x:find(fa[x]);
}
int check(){
for(int i=0;i<n;i++)fa2[i]=fa[i],fa[i]=i;
int tot=0;
for(int i=0;i<m;i++){
if(s[i]==0){
int x=find(U[i]),y=find(V[i]);
if(x!=y)fa[x]=y,tot++;
}
}if(tot==n-1){
return 1;
}
for(int i=0;i<n;i++)fa[i]=fa2[i];
return 0;
}
int dfs(int x,int y){
if(y==n-1)return check();
for(int i=x;i<m;i++){
int a=find(U[i]),b=find(V[i]);
if(a==b)continue;
fa[a]=b,s[i]=1;
if(dfs(i+1,y+1))return 1;
fa[a]=a,s[i]=0;
}return 0;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
while(cin>>n>>m){
if(n==-1&&m==-1)break;
for(int i=0;i<n;i++)fa[i]=i;
for(int i=0;i<m;i++)cin>>U[i]>>V[i],s[i]=0;
cout<<(dfs(0,0)?"YES":"NO")<<"\n";
}
}