JSOI2010 满汉全席
这个应该也算是一道2-SAT的入门题了……然后这题的读入倒是挺坑的。
题目描述很长,所以我很慢才提取出所需要的信息……后来发现,对于每种材料,他最后的呈现方式不是满式菜肴就是汉式菜肴,那么其实每一种材料都可以被看做是一个布尔变量,可以自定作为满/汉式为0,另一种为1.
然后发现要求满足所有评委至少一条要求,那就是对于每个评委取 || ,对于所有评委取 &&,那就是一个合取范式的形式啊!
此时做法就显而易见,把每种材料拆成两个点,之后按照给定的合取范式先转化,然后建图跑tarjan,判断一下是否合法即可。
不过这题读入真心坑……直接使用%c%d读入会出现异常错误,然后我天真的以为材料编号都是个位数(样例导致),就直接交了上去得了50.后来发现了这个问题改完了就过了……
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define fill(x,y) memset(x,y,sizeof(x)); #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 10005; const int N = 500005; const int INF = 1000000009; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct edge { int next,to,from; }e[M]; int k,n,m,ecnt,low[M],dfn[M],stack[M],top,idx,cnt,head[M],scc[M]; char s[10]; bool vis[M],flag; void clear() { memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(head,0,sizeof(head)); memset(scc,0,sizeof(scc)); cnt = idx = ecnt = flag = 0; } void add(int x,int y) { e[++ecnt].to = y; e[ecnt].from = x; e[ecnt].next = head[x]; head[x] = ecnt; } int rev(int x) { return x > n ? x - n : x + n; } void tarjan(int x) { low[x] = dfn[x] = ++idx; stack[++top] = x,vis[x] = 1; for(int i = head[x];i;i = e[i].next) { if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]); else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]); } if(dfn[x] == low[x]) { int p; cnt++; while((p = stack[top--])) { scc[p] = cnt,vis[p] = 0; if(x == p) break; } } } void init() { int cur = 1,a = 0,b = 0; scanf("%s",s); while(s[cur] >= '0' && s[cur] <= '9') { a *= 10; a += s[cur] - '0'; cur++; } if(s[0] == 'h') a += n; cur = 1; scanf("%s",s); while(s[cur] >= '0' && s[cur] <= '9') { b *= 10; b += s[cur] - '0'; cur++; } if(s[0] == 'h') b += n; //printf("%d %d\n",a,b); add(rev(a),b),add(rev(b),a); } int main() { k = read(); while(k--) { clear(); n = read(),m = read(); rep(i,1,m) init(); rep(i,1,n<<1) if(!dfn[i]) tarjan(i); rep(i,1,n) { if(scc[i] == scc[i+n]) { flag = 1; break; } } (flag) ? printf("BAD\n") : printf("GOOD\n"); } return 0; }
当你意识到,每个上一秒都成为永恒。