題目鏈接:CF662B Graph Coloring
顯然我們可以對於不同的顏色單獨考慮。
假設我們全部變爲‘B’,那麼如果當前邊是‘B’,我們只能選擇兩個端點全部改變,或者都不改變。
如果當前爲‘R’,那麼兩個端點一定是一個改變,一個不改變。
然後顯然可以直接2-SAT,現在就是怎麼對2-SAT求最小解的問題了。
我們假設點i爲改變,點i+n爲不改變,所以我們對於每個強連通分量單獨考慮,然後記錄聯通塊i,和聯通塊i+n,然後哪個裏面的小於n的點的個數更少,就以哪個爲基準即可。
AC代碼:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e5+10;
int n,m,dfn[N],low[N],vis[N],scc[N],num[N],cnt,co,a[N],b[N],flag[N],mark[N],res;
vector<int> g[N],v[N]; stack<int> s; char op[N][3];
void Tarjan(int x){
low[x]=dfn[x]=++cnt; vis[x]=1; s.push(x);
for(int to:g[x]){
if(!dfn[to]) Tarjan(to),low[x]=min(low[x],low[to]);
else if(vis[to]) low[x]=min(low[x],dfn[to]);
}
if(low[x]==dfn[x]){
int u; co++;
do{
u=s.top(); s.pop(); vis[u]=0; scc[u]=co;
if(u<=n) num[co]++; v[co].push_back(u);
}while(u!=x);
}
}
void solve(char ch){
for(int i=1;i<=2*n;i++) g[i].clear(),v[i].clear(),scc[i]=dfn[i]=low[i]=0;
memset(mark,0,sizeof mark),memset(num,0,sizeof num); cnt=co=0;
for(int i=1;i<=m;i++){
if(op[i][0]==ch){
g[a[i]].push_back(b[i]),g[b[i]].push_back(a[i]);
g[a[i]+n].push_back(b[i]+n),g[b[i]+n].push_back(a[i]+n);
}else{
g[a[i]].push_back(b[i]+n),g[b[i]].push_back(a[i]+n);
g[a[i]+n].push_back(b[i]),g[b[i]+n].push_back(a[i]);
}
}
for(int i=1;i<=n*2;i++) if(!dfn[i]) Tarjan(i);
for(int i=1;i<=n;i++) if(scc[i]==scc[i+n]) return ;
int tmp=0;
for(int i=1;i<=2*n;i++) if(!mark[i]){
if(num[scc[i]]<=num[scc[i+n]]){
tmp+=num[scc[i]];
for(int j:v[scc[i]]){
if(j<=n) mark[j]=1,mark[j+n]=2;
else mark[j]=1,mark[j-n]=2;
}
}else{
tmp+=num[scc[i+n]];
for(int j:v[scc[i+n]]){
if(j<=n) mark[j]=1,mark[j+n]=2;
else mark[j]=1,mark[j-n]=2;
}
}
}
if(tmp<res){
res=tmp; memset(flag,0,sizeof flag);
for(int i=1;i<=n*2;i++) if(mark[i]==1) flag[i]=1;
}
}
signed main(){
cin>>n>>m; res=1e9;
for(int i=1;i<=m;i++) scanf("%d %d %s",&a[i],&b[i],op[i]);
solve('R'),solve('B');
if(res==1e9) return puts("-1"),0;
cout<<res<<endl;
for(int i=1;i<=n;i++) if(flag[i]==1) printf("%d ",i);
return 0;
}