EGOI2024 部分題解

Rainbow_qwq發表於2024-08-15

Light Bulbs / 燈泡安裝

隨機化 heuristic problem.

Make Them Meet / 活動面基

在某一輪中,稱兩個點被染上同一種顏色且它們在原圖上有連邊為“連邊”。

對於一條鏈的構造

奇數輪連邊 \((1,2),(3,4),(5,6),\dots\),偶數輪連邊 \((2,3),(4,5),(6,7),\dots\)。這樣每個人會在鏈上不斷迴圈走,經過 \(2n\) 輪後,兩個人一定會相遇。

對於一棵樹的構造

取任意一個節點為根,dfs 整棵樹。

奇數輪連所有 \(dep\) 為奇數的點 \(u\)\(fa_u\) 的邊,偶數輪則連所有 \(dep\) 為偶數的點的父親邊。同時在每一輪中,都連上 \((rt,son)\) 的邊,其中 \(son\)\(rt\) 的任意一個兒子。

容易發現,一個點可能先往下走到一個葉子再往上走,在走到 \(rt\) 之後就會一直在 \((rt,son)\) 的邊上不停迴圈。

這樣在 \(2n\) 輪後,兩個人一定會在 \((rt,son)\) 的邊上相遇。

對於一般圖的構造

對於上述樹的構造,我們發現只要滿足以下的條件就能套用到圖上:

  • 對於任意一個點 \(u\)\(u\) 的所有兒子之間沒有連邊。(在給 \(u\) 和兒子染同種顏色時不會走錯)
  • 對於根節點 \(rt\),需要選出一個兒子 \(son\),使得 \(rt\)\(son\) 的所有兒子沒有連邊。(在給 \(rt,son\) 和這些點染同種顏色時不會走錯)

考慮先建一棵 dfs 樹,然後分類討論。

若 dfs 樹為一條鏈,則可直接套用鏈的做法。

否則,我們可以找到一個分叉點 \(u\),使得 \(u\) 是最深的分叉點。則 \(u\) 的所有兒子子樹都是鏈。

\(u\) 的父親節點為 \(f\)

\(u\) 有一個兒子 \(v\) 使得 \(v,f\) 沒有連邊,則可以從 \(v\) 開始重新求一棵 dfs 樹,並且優先 dfs \(v\to u\to f \dots\)。這樣 \(u\) 在新 dfs 樹中的兒子只可能是 \(f\)\(u\) 的其他兒子,\(v\) 與它們沒有連邊。取 \(rt=v,son=u\) 就構造完畢。

否則,\(u\) 的所有兒子都和 \(f\) 有連邊。任意取一個兒子 \(v\),從 \(v\) 開始重新求一棵 dfs 樹,並且優先 dfs \(v\to u\to \{son_u\}\),其中 \(\{son_u\}\)\(u\) 的其他兒子。由於 \(u\) 的其他兒子與 \(f\) 有連邊,所以原樹在 \(f\) 之上的部分會在 \(u\) 的其他兒子下方被 dfs 到,不會成為新樹中 \(u\) 的兒子。那麼 \(v\)\(u\) 的兒子沒有連邊,取 \(rt=v,son=u\) 構造完畢。

時間複雜度 \(O(n)\) 且操作次數為 \(2n\) 輪。

// what is matter? never mind. 
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("unroll-loops")
//#pragma GCC target("sse,sse2,sse3,sse4,popcnt,abm,mmx,avx,avx2") 
#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define int long long
#define ull unsigned long long
#define SZ(x) ((int)((x).size()))
#define ALL(x) (x).begin(),(x).end()
using namespace std;

#define fi first
#define se second
#define pb push_back
#define mkp make_pair
typedef pair<int,int>pii;
typedef vector<int>vi;

#define maxn 200006
#define inf 0x3f3f3f3f

int n,m,rt;
int e[105][105],deg[105];
vi g[105];

int fa[105],dep[105];
vi son[105];
vi que;

bool del[105];

void dfs(int u,int pa){
	que.pb(u);
	fa[u]=pa,dep[u]=dep[pa]+1;
	for(int v:g[u])
		if(v!=pa && !dep[v]) son[u].pb(v),dfs(v,u);
}
int col[maxn];

void chain(vi o){
	cout<<n*2<<"\n";
	For(i,1,n*2){
		For(j,0,n-1) {
			if((j&1)==(i&1) && j) col[o[j]]=o[j-1];
			else col[o[j]]=o[j];
		}
		For(u,1,n) cout<<col[u]<<" "; cout<<"\n";
	}
	exit(0);
}

void out(int rt,int dw){
	cout<<n*2<<"\n";
	For(t,1,n*2){
		For(i,1,n){
			if(i==rt) {
				if(t&1) cout<<dw<<" ";
				else cout<<rt<<" ";
			}else{
				if((t&1)==(dep[i]&1)) cout<<fa[i]<<" ";
				else cout<<i<<" ";
			}
		}
		cout<<"\n";
	}
	exit(0);
}

void dfs2(int u,int pa){
//	cout<<"Dfs2 "<<u<<" "<<pa<<" "<<dep[pa]<<"\n";
	fa[u]=pa,dep[u]=dep[pa]+1;
	for(int v:g[u])
		if(v!=pa && !dep[v] && !del[v]) dfs2(v,u);
}

vi g2[105];
void dfsc(int u,int pa){
	que.pb(u);
	for(int v:g2[u]) if(v!=pa) dfsc(v,u);
}

signed main()
{
	n=read(),m=read();
	
	For(i,1,m){
		int u=read(),v=read();
		++u,++v;
		e[u][v]=e[v][u]=1;
		++deg[u],++deg[v];
		g[u].pb(v),g[v].pb(u);
	}
	
	dfs(1,0);
	
	bool ok1=1;
	For(i,1,n)
		for(int v:son[i]) g2[i].pb(v),g2[v].pb(i);
	For(i,1,n) ok1&=(g2[i].size()<=2);
	if(ok1){
		int u=1;
		For(i,1,n) if(g2[i].size()==1) u=i;
		que.clear();
		dfsc(u,0);
		chain(que);
		exit(0);
	}
	
	int u=0;
	For(i,1,n) if(son[i].size()>1 && dep[i]>=dep[u]) u=i;
	int f=fa[u];
	if(!f){
		For(i,1,n) son[i].clear(),fa[i]=dep[i]=0; que.clear();
		int v=son[u][0];
		dfs(v,0);
		u=0;
		For(i,1,n) if(son[i].size()>1 && dep[i]>=dep[u]) u=i;
		f=fa[u];
		assert(f);
	}
	
	del[u]=1;
	for(int v:son[u])
		if(!e[v][f]) {
			g[v].insert(g[v].begin(),u);
			g[u].insert(g[u].begin(),f);
			For(i,1,n) son[i].clear(),fa[i]=dep[i]=del[i]=0; que.clear();
			dfs2(v,0);
			out(v,u);
			exit(0);
		}
//	assert(0);
	
	int v=son[u][0];
	for(int x:son[u])
		if(x!=v) g[u].insert(g[u].begin(),x);
	g[v].insert(g[v].begin(),u);
	For(i,1,n) son[i].clear(),fa[i]=dep[i]=del[i]=0; que.clear();
	dfs2(v,0);
	out(v,u);
	return 0;
}
/*

*/

相關文章