解题思路
每个菜品分为满式和汉式两个点,若选了A点就必选B点则由A向B连边。最后Tarjan缩点,若存在一个菜品的满式和汉式在一个强连通分量中,则该方案不合法。
代码:
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<stack>
using namespace std;
stack <int> q;
int hed[205],nex[2005],lb[2005];
int low[205],dfn[205],block[205];
int Y,n,m,T,lo,tot;
inline int read(){
int ret=0;
char opt[10];
scanf("%s",opt);
int len=strlen(opt);
for(int i=1;i<len;i++)
ret=ret*10+opt[i]-'0';
ret=ret<<1|(opt[0]=='h');
return ret;
}
void add(int x,int y){
lo++;
nex[lo]=hed[x];
hed[x]=lo;
lb[lo]=y;
}
void dfs(int x){
low[x]=dfn[x]=++T;q.push(x);
for(int i=hed[x];i!=0;i=nex[i]){
if(!dfn[lb[i]]){
dfs(lb[i]);
low[x]=min(low[x],low[lb[i]]);
}
else if(!block[lb[i]]) low[x]=min(low[x],dfn[lb[i]]);
}
if(low[x]==dfn[x]){
tot++;
int xx=0;
while(xx!=x){
xx=q.top();q.pop();
block[xx]=tot;
}
}
}
void Tarjan(){
for(int i=2;i<=n*2+1;i++)
if(!dfn[i]) dfs(i);
for(int i=2;i<=n*2+1;i++)
if(block[i]==block[i^1]){
printf("BAD\n");
return ;
}
printf("GOOD\n");
}
int main(){
scanf("%d",&Y);
while(Y--){
memset(hed,0,sizeof(hed));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(block,0,sizeof(block));
T=lo=tot=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a=read(),b=read();
add(a^1,b);add(b^1,a);
}
Tarjan();
}
return 0;
}