【Atcoder】 [ARC161E] Not Dyed by Majority (Cubic Graph)

题目链接

Atcoder方向
Luogu方向

题目解法

首先如果知道一个方案,可以用 2 − S A T 2-SAT 2SAT 判断这个方法是否可行
可以发现 2 − S A T 2-SAT 2SAT 图中共有 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;
}

你可能感兴趣的:(Atcoder,算法)