CF1110G Tree-Tac-Toe 博弈論、構造


傳送門

UPD:之前可能對白色變無色的過程講的不是很清楚,已經補充


顯然在雙方絕頂聰明的情況下,黑色不可能贏

首先考慮樹上一個白色的點都沒有的情況:

1、如果樹上有一個點的度數\(\geq 4\),白色必贏,只需要第一次將這一個點染成白色,接着隨便染它的兩個鄰居就可以達成目標

2、如果樹上有一個點的度數\(=3\),且它所連的\(3\)個點之間至少有\(2\)個點不是葉子節點,白色必贏,只需要第一次染這一個點,第二次染它的一個非葉子鄰居,第三次就一定至少存在一個未被染色的點與這兩個相鄰。

那么剩下的情況,樹的形態只會是下圖中的三種

但是還沒完(我以為到這里就完了結果WA2被Tutorial點名)

最重要的3、如果樹的形態是上面的圖中最下面的那一種,而且總點數為奇數,那么白色必贏

圖長下面這樣,中間的……省略的是一條鏈,編號從左往右遞增。

白色最開始染\(2\)號點,黑色如果染\(3\)號點白色直接染\(1\)號點,所以黑色必須染\(1\)號點。此時白色染\(4\)號點,黑色又只能染\(3\)號點……如是白色染到\(2N\)號點,黑色染\(2N-1\)號點之后,白色染\(2N+1\)號點,那么最右邊就會有兩個未被染的點,白色就贏了

其余的情況顯然都是Draw的

然后考慮已經被染成白色的點的影響,最開始天真的我想直接各種特判過掉,結果WA14不曉得怎么回事

我們已經考慮了樹上沒有被染成白色的點的所有情況,那么能否將一個已經被染成白色的點等價為若干未被染成白色的點?實際上是可以的

假設下圖中\(1\)號點在原樹上是一個白色點,那就在保留它原來的鄰居的基礎上給它額外連上\(3\)個點,連成下面的\(ABCD\)結構

原圖\(1\)號點對應新圖的\(A\)號點,原圖上\(1\)號點跟哪些點連了邊,新圖上\(A\)號點也和它們連邊,然后在下面掛上\(BCD\)三個點

對於執白色的人來說,如果TA在某一回合塗白了\(A\)號點,這個時候如果執黑色者不塗黑\(B\)號點,那么執白色者將會在下一回合塗白\(B\)號點,對於\(CD\)兩個點,白色就一定可以塗白其中一個,白色就贏了

所以執黑色者只能塗黑\(B\)號點。而這個時候\(BCD\)三個點對於勝負已經沒有影響了,可以直接砍掉這三個點,就相當於白色直接塗白了\(A\)號點,也就是塗白了原圖的\(1\)號點,然后又來到白色的回合。

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c)){
	    if(c == '-')
			f = 1;
        c = getchar();
    }
    while(isdigit(c)){
		a = (a << 3) + (a << 1) + (c ^ '0');
		c = getchar();
	}
	return f ? -a : a;
}

const int MAXN = 1e6 + 9;
struct Edge{
	int end , upEd;
}Ed[MAXN << 1];
int head[MAXN] , in[MAXN] , N , cntEd , cnt;
char s[MAXN];

inline void addEd(int a , int b){
	Ed[++cntEd].end = b;
	Ed[cntEd].upEd = head[a];
	head[a] = cntEd;
	++in[a];
}

int main(){
	for(int T = read() ; T ; --T){
		N = read();
		cntEd = 0;
		memset(head , 0 , sizeof(int) * (N + 1));
		memset(in , 0 , sizeof(int) * (N + 1));
		for(int i = 1 ; i < N ; ++i){
			int a = read() , b = read();
			addEd(a , b);
			addEd(b , a);
		}
		scanf("%s" , s + 1);
		if(N < 3){
		    puts("Draw");
		    continue;
		}
		if(N == 3){
		    int cnt = 0;
		    for(int i = 1 ; i <= N ; ++i)
		        cnt += s[i] == 'W';
		    puts(cnt >= 2 ? "White" : "Draw");
		    continue;
		}
		bool ifans = 0;
		int cnt1 = 0;
		for(int i = 1 ; i <= N ; ++i)
		    if(s[i] == 'W'){
		        addEd(i , ++N);
		        head[N] = 0;
		        addEd(N , i);
		        in[N] = 3;
		    }
		for(int i = 1 ; !ifans && i <= N ; ++i)
			if(in[i] > 3)
				ifans = 1;
			else
				if(in[i] == 3){
					int cnt = 0; 
					for(int j = head[i] ; j ; j = Ed[j].upEd)
						cnt += in[Ed[j].end] >= 2;
					ifans = cnt >= 2;
					++cnt1;
			}
		if(cnt1 == 2 && (N & 1))
		    ifans = 1;
		puts(ifans ? "White" : "Draw");
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM