Atcoder方向
Luogu方向
首先如果知道一个方案,可以用 2 − S A T 2-SAT 2−SAT 判断这个方法是否可行
可以发现 2 − S A T 2-SAT 2−SAT 图中共有 6 n 6n 6n 条边, 2 n 2n 2n 个点
不难发现会有很大概率出现 i i i 与 i + n i+n i+n 出现在同一个强连通分量中
这也可以打表(或者根据c题的经验)得出不可行的方案的概率 > 1 2 >\frac{1}{2} >21
这就启发我们随机答案,判断答案是否可行
这道题启发我们:如果答案方案在总方案中占比较大,可以采用随机+判断的方式
#include
using namespace std;
const int N(100100);
int c[N];
int e[N<<2],ne[N<<2],h[N],idx;
int low[N],dfn[N],dfs_clock,scc_num[N],scc_cnt;
int stk[N],top;
vector<int> vec[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void tarjan(int u){
dfn[u]=low[u]=++dfs_clock;
stk[++top]=u;
for(int i=h[u];~i;i=ne[i]){
int v=e[i];
if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
else if(!scc_num[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
scc_num[u]=++scc_cnt;
while(u!=stk[top]) scc_num[stk[top--]]=scc_cnt;
top--;
}
}
void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
void work(){
int n=read();
for(int i=1;i<=n;i++) vec[i].clear();
for(int i=1,x,y;i<=n/2*3;i++) x=read(),y=read(),vec[x].push_back(y),vec[y].push_back(x);
while(true){
idx=dfs_clock=scc_cnt=top=0;
for(int i=1;i<=n<<1;i++) h[i]=-1,dfn[i]=low[i]=scc_num[i]=0;
for(int i=1;i<=n;i++){
c[i]=rand()%2;
int x1=vec[i][0],x2=vec[i][1],x3=vec[i][2];
if(c[i]==0) add(x1+n,x2),add(x1+n,x3),add(x2+n,x1),add(x2+n,x3),add(x3+n,x1),add(x3+n,x2);
else add(x1,x2+n),add(x1,x3+n),add(x2,x1+n),add(x2,x3+n),add(x3,x1+n),add(x3,x2+n);
}
// cout<<"+++";
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
bool flg=0;
for(int i=1;i<=n;i++) if(scc_num[i]==scc_num[i+n]){ flg=1;break;}
if(flg){
for(int i=1;i<=n;i++) putchar(c[i]?'B':'W');
puts("");break;
}
}
}
int main(){
srand(time(NULL));
int T=read();
while(T--) work();
return 0;
}