• 题解 Christmas Game


    题目传送门

    题目大意

    给出 (t)(n) 个点 (m) 条边的无向图,每次可以从任意一棵树选择一条边删掉,然后该树不与根(为 (1) )联通的部分被删掉。不能操作的人输。问谁有必胜策略。

    每棵树都满足:每个环都只会挂在叶子节点上。

    (nle 100,mle 500)

    思路

    怎么说呢?很厉害的题目吧。

    首先考虑一个树的情况,我们设 (sg(u)) 表示 (u) 子树内的 (sg) 函数值,我们可以得到转移式:

    [sg(u)= ext{mex}_{vin son_u}{sg(v)} ]

    [Rightarrow sg(u)=otimes_{vin son_u} (sg(v)+1) ]

    这个可以通过打表发现,不过有一种比较巧妙的方法,就是说我们把主链拉出来,那么相当于每一个节点连了一条链,那么,删边就相当于取石子了。

    然后考虑拓展到任意图上。这里给出一个结论:

    一个环如果大小为偶数,它的顶点产生的贡献为 (0),反之为 (1)

    相当于环大小为偶数时,把环缩为一个点,否则再连向一个点。

    考虑证明,我们发现我们可以通过枚举破掉环上哪条边来求,你发现环大小为偶数时,你破掉之后两条链长度一定一奇一偶,也就是对该环的根(挂的叶子)产生的贡献一定为偶数,所以第一个未出现的正整数一定为 (1)。同理,我们可以推出环大小为奇数的情况,这里就不再赘述了。

    这里提醒一些细节:

    • 需要考虑重边

    • 需要考虑多个环串在一个顶点的情况

    具体见代码就好了。

    ( exttt{Code1})

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 105
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int T,n,m,sg[MAXN],dep[MAXN],vis[MAXN];
    
    int toop,head[MAXN],to[MAXN * 10],nxt[MAXN * 10];
    
    void Add_Edge (int u,int v){
    	to[++ toop] = v,nxt[toop] = head[u],head[u] = toop;
    	to[++ toop] = u,nxt[toop] = head[v],head[v] = toop;
    }
    
    int dfs (int u,int fa){
    	bool flag = 0;
    	dep[u] = dep[fa] + 1,vis[u] = 1;
    	for (Int i = head[u];i;i = nxt[i]){
    		int v = to[i];
    		if (!v) continue;
    		if (v == fa && !flag){
    			flag = 1;
    			continue;
    		}
    		if (vis[v]){
    			sg[v] ^= (dep[u] - dep[v] + 1 & 1);
    			to[i ^ 1] = 0;
    			return v;
    		}
    		else{
    			int cur = dfs (v,u);
    			if (!cur) sg[u] ^= sg[v] + 1;
    			else if (cur ^ u) return cur;
    		}
    	}
    	return 0;
    }
    
    void clear (){
    	toop = 1,memset (head,0,sizeof (head));
    	for (Int i = 1;i <= n;++ i) sg[i] = dep[i] = vis[i] = 0;
    }
    
    signed main(){
    	while (~scanf ("%d",&T)){
    		int ans = 0;
    		while (T --> 0){
    			read (n),read (m),clear ();
    			for (Int i = 1,u,v;i <= m;++ i) read (u),read (v),Add_Edge (u,v);
    			dfs (1,0),ans ^= sg[1];
    		}
    		puts (ans ? "Sally" : "Harry");
    	} 
    	return 0;
    }
    

    ( exttt{Code2})

    #include <cstdio>
    #include <vector>
    using namespace std;
    
    #define Int register int
    #define MAXN 105
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    vector <int> G[MAXN];
    int T,n,m,top,sg[MAXN],dep[MAXN],vis[MAXN],sta[MAXN];
    
    void Add_Edge (int u,int v){
    	G[u].push_back (v),
    	G[v].push_back (u);
    }
    
    void dfs (int u,int fa){
    	bool flag = 0;
    	sta[++ top] = u,vis[u] = 1;
    	for (Int i = 0;i < G[u].size();++ i){
    		int v = G[u][i];
    		if (v == fa && !flag){
    			flag = 1;
    			continue;
    		}
    		if (vis[v] == 1){
    			int cnt = 1;
    			while (sta[top] != v){
    				cnt ++;
    				vis[sta[top --]] = 0;
    			}
    			sg[v] ^= (cnt & 1);
    		}
    		else if (vis[v] == -1){
    			dfs (v,u); 
    			if (vis[v]) sg[u] ^= sg[v] + 1;
    		}
    	}
    	if (vis[u]) -- top;
    	return ;
    }
    
    void clear (){
    	top = 0;
    	for (Int i = 1;i <= n;++ i) sg[i] = dep[i] = 0,vis[i] = -1,G[i].clear ();
    }
    
    signed main(){
    	while (~scanf ("%d",&T)){
    		int ans = 0;
    		while (T --> 0){
    			read (n),read (m),clear ();
    			for (Int i = 1,u,v;i <= m;++ i){
    				read (u),read (v);
    				if (u ^ v) Add_Edge (u,v);
    			}
    			dfs (1,0),ans ^= sg[1];
    		}
    		puts (ans ? "Sally" : "Harry");
    	} 
    	return 0;
    }
    
  • 相关阅读:
    笔记本硬盘接口SATA, PATA
    dB和dBm的区别
    SQL Server 存储过程分页方案比较
    SQL Server 输出参数OUTPUT
    安装iis5.1时找不到zClientm.exe的解决方法
    mac os x 10.5.8不通本网段
    SQL Server 存储过程分页大全(2005,2000)
    硬盘保修查询网站明细清单希捷硬盘保修查询西数硬盘保修查
    如何让SWT的窗口置顶(总在最上面)?
    ASP.NET(三) Web开发——常用服务器控件
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13747179.html
Copyright © 2020-2023  润新知