「coci 2021-2022 #1」Logičari
阿新 • • 發佈:2022-01-02
斷環後把斷的邊所連的兩個點特殊標記,作為兩個特殊點。這樣就是一個樹,樹的做法很簡單吧,把兩個特殊點特殊處理帶進狀態即可。
具體一點就是,設 \(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; }