简单$2-SAT$题,为每个人设置$0/1$值,
代表是坐新娘还是新郎那边,
为三种关系建图:
-
新娘和新郎对着坐
-
每个家庭的夫妻对着坐
-
$m$对不能一起坐在新娘对面的人
为了不易错,可以把每个人的编号记下来。
我写了两种输出解的方式,一种是$topsort$,另一种是利用$SCC$的编号。
两种方法均可。
$Code:$
#include<bits/stdc++.h>
using namespace std;
const int N=8e5+10;
int n,m,cnt,c[N],Ed=0;
int pre[N],now[N],to[N],tot;
int h[N][2],w[N][2],opp[N],deg[N];
int low[N],dfn[N],num,sk[N],top,val[N];
bool vis[N];
struct{
int x,y;
}E[N];
void add(int x,int y){
if(!num){
Ed++;
E[Ed].x=x;
E[Ed].y=y;
}
pre[++tot]=now[x];
now[x]=tot;to[tot]=y;
}
void Clear(){
tot=1;top=cnt=num=Ed=0;
memset(low,0,sizeof(low));
memset(now,0,sizeof(now));
memset(vis,0,sizeof(vis));
memset(opp,0,sizeof(opp));
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
memset(deg,0,sizeof(vis));
memset(val,0,sizeof(val));
}
void Pre(){
for(int i=0;i<n;i++)h[i][0]=i;
w[0][0]=h[n-1][0]+1;
for(int i=1;i<n;i++)w[i][0]=w[i-1][0]+1;
h[0][1]=w[n-1][0]+1;
for(int i=1;i<n;i++)h[i][1]=h[i-1][1]+1;
w[0][1]=h[n-1][1]+1;
for(int i=1;i<n;i++)w[i][1]=w[i-1][1]+1;
}
void tarjan(int u){
low[u]=dfn[u]=++num;
vis[sk[++top]=u]=true;
for(int i=now[u];i;i=pre[i]){
int v=to[i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
int v;cnt++;
do{
v=sk[top--];
vis[v]=false;
c[v]=cnt;
}while(u!=v);
}return;
}
//void topsort(){
// queue<int>q;
// memset(now,tot=0,sizeof(now));
// for(int i=1;i<=Ed;i++){
// if(c[E[i].x]==c[E[i].y])
// continue;
// add(c[E[i].y],c[E[i].x]);
// deg[c[E[i].x]]++;
// }
// for(int i=1;i<=cnt;i++)
// if(!deg[i])q.push(i);
// while(q.size()){
// int u=q.front();q.pop();
// if(!val[u]){
// val[u]=1;
// val[opp[u]]=2;
// }
// for(int i=now[u];i;i=pre[i]){
// int v=to[i];
// if(!--deg[v])q.push(v);
// }
// }
// for(int i=1;i<n;i++)
// if(val[c[i]]==2)printf("%dh ",i);
// else printf("%dw ",i);
// puts("");
//}
int main(){
while(~scanf("%d%d",&n,&m)&&n&&m){
Clear();
Pre();
for(int i=1;i<n;i++){
add(h[i][1],w[i][0]);
add(w[i][1],h[i][0]);
add(h[i][0],w[i][1]);
add(w[i][0],h[i][1]);
}
add(w[0][0],w[0][1]);
add(h[0][1],h[0][0]);
for(int i=1;i<=m;i++){
char op1,op2;int a,b,A,B;
scanf("%d%c%d%c",&a,&op1,&b,&op2);
if(op1=='h'&&op2=='h'){
add(h[a][0],h[b][1]);
add(h[b][0],h[a][1]);
}
if(op1=='h'&&op2=='w'){
add(h[a][0],w[b][1]);
add(w[b][0],h[a][1]);
}
if(op1=='w'&&op2=='h'){
add(w[a][0],h[b][1]);
add(h[b][0],w[a][1]);
}
if(op1=='w'&&op2=='w'){
add(w[a][0],w[b][1]);
add(w[b][0],w[a][1]);
}
}
for(int i=0;i<=w[n-1][1];i++)
if(!dfn[i])tarjan(i);
bool flag=true;
for(int i=0;i<n;i++){
if(c[h[i][0]]==c[h[i][1]]){flag=false;break;}
if(c[w[i][0]]==c[w[i][1]]){flag=false;break;}
opp[c[w[i][0]]]=c[w[i][1]];
opp[c[w[i][1]]]=c[w[i][0]];
opp[c[h[i][0]]]=c[h[i][1]];
opp[c[h[i][1]]]=c[h[i][0]];
}
if(!flag)puts("bad luck");
else{
for(int i=1;i<n;i++){
if(c[h[i][0]]<c[h[i][1]])
printf("%dw ",i);
else printf("%dh ",i);
}
puts("");
}
}
return 0;
}
# Orz