题目大意:有n种材料,m个评委。每种材料有两种不同的做法,每个评委有两个判定标准,做出来的菜品必须满足每一个评委至少一个要求。问有没有这样的方案。
思路:2-SAT经典建图问题。因为每一种材料只能有两种做法,这种约束条件通常就想到2-SAT。每一个评委必须至少满足一种,这就是建图的条件。
所以连边A‘ -> B
B’ -> A
这样表示的是如果A不能满足某个评委,那么就必须让b满足这个评委。
然后就是Tarjan缩点,判断是否有个菜品的两种做法在一个scc中,若有就是无解,没有就是有解。
CDOE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 5010 using namespace std; int cases; int points,cnt; int head[MAX],_total; int _next[MAX],aim[MAX]; int dfn[MAX],low[MAX],total; int stack[MAX],top; bool in_stack[MAX]; int changed[MAX],scc; char c1,c2; inline void Initialize(); inline void Add(int x,int y); void Tarjan(int x); int main() { for(cin >> cases;cases; --cases) { scanf("%d%d",&points,&cnt); Initialize(); for(int x,y,i = 1;i <= cnt; ++i) { getchar(); scanf("%c%d %c%d",&c1,&x,&c2,&y); x = (x << 1) + (c1 == 'h'); y = (y << 1) + (c2 == 'h'); Add(x^1,y); Add(y^1,x); } for(int i = 2;i <= (points << 1|1); ++i) if(!dfn[i]) Tarjan(i); bool flag = true; for(int i = 1;i <= points; ++i) if(changed[i << 1] == changed[i << 1|1]) flag = false; if(flag) puts("GOOD"); else puts("BAD"); } return 0; } inline void Initialize() { total = _total = top = scc =0; memset(dfn,0,sizeof(dfn)); memset(head,0,sizeof(head)); memset(in_stack,false,sizeof(in_stack)); } inline void Add(int x,int y) { _next[++_total] = head[x]; aim[_total] = y; head[x] = _total; } void Tarjan(int x) { dfn[x] = low[x] = ++total; stack[++top] = x; in_stack[x] = true; for(int i = head[x];i;i = _next[i]) { if(!dfn[aim[i]]) Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]); else if(in_stack[aim[i]]) low[x] = min(low[x],dfn[aim[i]]); } if(low[x] == dfn[x]) { scc++; int temp; do { temp = stack[top--]; changed[temp] = scc; in_stack[temp] = false; }while(temp != x); } }
时间: 2024-11-05 02:24:58