1. 程式人生 > 其它 >「coci 2021-2022 #1」Logičari

「coci 2021-2022 #1」Logičari

link。

斷環後把斷的邊所連的兩個點特殊標記,作為兩個特殊點。這樣就是一個樹,樹的做法很簡單吧,把兩個特殊點特殊處理帶進狀態即可。

具體一點就是,設 \(f(x,c_x,c_f,c_{rt_1},c_{rt_2})\) 表示處理到 \(x\) 點,\(x\) / \(x\) 的前驅 / 特殊點 1 / 特殊點 2 是否染色,轉移很基礎,具體看程式碼(程式碼中寫的是狀壓)。

注意判無解……

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define cmin(x, y) x = min(x, y)
#define cmax(x, y) x = max(x, y)
template<typename T=int> inline T read() {
	T x=0; char c=getchar(); bool f=0;
	while(c<'0' || c>'9')	f|=c=='-',c=getchar();
	while(c>='0' && c<='9')	x=x*10+(c&15),c=getchar();
	return f?-x:x;
}
__attribute__((target("avx"), optimize("O3", "unroll-loops")))
const int INF=1e9+7;
int n,fa[100100],rt,exrt,dp[100100][17];
vector<int> e[100100];
int makeSta(vector<int> v) {
	int res=0; assert(v.size()==4u);
	for(int i=0; i<4; ++i) {
		res+=(1<<(3-i))*v[i];
		assert(0<=v[i] && v[i]<=1);
	}
	return res;
}
int GetAns(const int now,const int f,const int Sta) {
	// Sta: colnow(3), colf(2), colrt(1), colexrt(0)
	if(~dp[now][Sta])	return dp[now][Sta];
	if((now==rt && ((Sta>>3)&1)!=((Sta>>1)&1))
		|| (now==exrt && (((Sta>>3)&1)!=(Sta&1))) || (now==exrt && (Sta>>2)&1 && (Sta>>1)&1))	return dp[now][Sta]=INF;
	int cnt=(Sta>>3)&1,res=INF; // number of vertexes coloured
	for(const int y:e[now])	if(y!=f)	cnt+=GetAns(y,now,makeSta({0,(Sta>>3)&1,(Sta>>1)&1,Sta&1}));
	if((Sta>>2)&1 || (now==rt && Sta&1) || (now==exrt && (Sta>>1)&1))	cmin(res,cnt);
	else {
		for(const int y:e[now])	if(y!=f)	cmin(res,cnt-GetAns(y,now,makeSta({0,(Sta>>3)&1,(Sta>>1)&1,Sta&1}))
			+GetAns(y,now,makeSta({1,(Sta>>3)&1,(Sta>>1)&1,Sta&1})));
	}
	return dp[now][Sta]=res;
}
int find(int now) { while(now!=fa[now])	now=fa[now]=fa[fa[now]]; return now; }
signed main() {
	// freopen("logicians.in","r",stdin);
	// freopen("logicians.out","w",stdout);
	memset(dp,-1,sizeof dp);
	n=read();
	for(int i=1; i<=n; ++i)	fa[i]=i;
	for(int i=1,x,y; i<=n; ++i) {
		x=read(),y=read();
		if(find(x)!=find(y)) {
			fa[find(x)]=find(y);
			e[x].push_back(y);
			e[y].push_back(x);
		}
		else	rt=x,exrt=y;
	}
	int ret=INF;
	for(const int i:{0,1})	for(const int j:{0,1})	cmin(ret,GetAns(rt,0,makeSta({i,0,i,j})));
	if(ret==INF)	return puts("-1"),0;
	printf("%lld\n",ret);
	return 0;
}