洛谷 P4171 [JSOI]满汉全席
最近刚刚学的2-sat,就刷了这道裸题。
2-sat问题一般是用tarjan求的,当出现(x,y)或(!x,y)或(x,!y)三种选择时,我们可以把!x->y,!y->x连边。
然后直接tarjan。
比如这一题,设汉菜为是,满菜为非,直接按上面所述连边跑tarjan,判断是与非是否在同一强连通分量中。
在,就输出BAD,不在,则输出GOOD。
code:
#include <bits/stdc++.h>
using namespace std;
const int N=10005;
int n,m,dfscnt,scc;
int s[N<<5][2],o[N];
int dfn[N],low[N],sccno[N];
stack <int> sta;
void add(int x,int y)
{
s[++o[0]][1]=o[x],s[o[0]][0]=y,o[x]=o[0];
}
void tarjan(int x)
{
sta.push(x);
low[x]=dfn[x]=++dfscnt;
for (int i=o[x];i;i=s[i][1]) {
int y=s[i][0];
if (!dfn[y])
tarjan(y),low[x]=min(low[x],low[y]);
else if (!sccno[y])
low[x]=min(low[x],dfn[y]);
}
if (dfn[x]==low[x]) {
++scc;
while (1) {
int y=sta.top();
sta.pop();
sccno[y]=scc;
if (x==y) break;
}
}
}
int main()
{
int T;cin>>T;
while (T--) {
memset(o,0,sizeof(o));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(sccno,0,sizeof(sccno));
scc=dfscnt=0;
scanf("%d%d",&n,&m);
char a,b;
int pa,pb;
for (int i=1;i<=m;++i) {
cin>>a>>pa>>b>>pb;
int aval,bval,nota,notb;
if (a=='h') aval=1;
else aval=0;
if (b=='h') bval=1;
else bval=0;
nota=aval^1,notb=bval^1;
add(pa+nota*n,pb+bval*n);
add(pb+notb*n,pa+aval*n);
}
for (int i=1;i<=(n<<1);++i)
if (!dfn[i]) tarjan(i);
bool flag=1;
for (int i=1;i<=n;++i)
if (sccno[i]==sccno[i+n]) {
puts("BAD");
flag=0;
break;
}
if (flag) puts("GOOD");
}
return 0;
}