兩道2-SAT模板題。git
看題目就一眼2-SAT。一對夫妻當作一個變量,之間的矛盾能夠當作限制。spa
考慮不一樣席的限制,至關於選了\(i\)就不選\(j\),即必選\(j'\)。因此咱們\(i\to j',j\to i'\)連邊便可。code
Tarjan判一發可行性便可。注意一下編號從\(0\)開始。遞歸
CODEstring
#include<cstdio> #include<cctype> #include<cstring> using namespace std; const int N=1005; struct edge { int to,next; }e[(N*N)<<1]; int head[N<<1],dfn[N<<1],low[N<<1],stack[N<<1],col[N<<1],n,m,cnt,tot,top,scc,x1,x2,y1,y2; bool vis[N<<1]; inline void add(int x,int y) { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } inline int min(int a,int b) { return a<b?a:b; } inline void Tarjan(int now) { dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1; for (register int i=head[now];~i;i=e[i].next) if (!dfn[e[i].to]) Tarjan(e[i].to),low[now]=min(low[now],low[e[i].to]); else if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]); if (dfn[now]==low[now]) { col[now]=++scc; vis[now]=0; while (now!=stack[top]) col[stack[top]]=scc,vis[stack[top--]]=0; --top; } } inline void clear(void) { memset(head,-1,sizeof(head)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); cnt=tot=top=scc=0; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; start: while (scanf("%d%d",&n,&m)!=EOF) { for (clear(),i=1;i<=m;++i) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); add((x1<<1)+x2,(y1<<1)+(!y2)); add((y1<<1)+y2,(x1<<1)+(!x2)); } for (i=0;i<(n<<1);++i) if (!dfn[i]) Tarjan(i); for (i=0;i<n;++i) if (col[i<<1]==col[(i<<1)+1]) { puts("NO"); goto start; } puts("YES"); } }
題目大意:現有\(n\)個黨派,每一個黨派須要在兩個表明中選一個,這\(2n\)個表明中有彼此討厭的\(m\)對人,輸出\(n\)個去開會的表明(多解則輸出字典序最小解)it
又是互相厭惡,這就很好辦了,直接套上一題的建圖方法,而後暴力DFS,中間清空標記。io
字典序最小的話就優先選擇\(i'\),清空的時候不要ZZ同樣的memset,開一個棧存一下遞歸到的點。模板
其餘的都是板子。CODEclass
#include<cstdio> #include<cctype> #include<cstring> using namespace std; const int N=8005,M=20005; struct edge { int to,next; }e[M<<1]; int head[N<<1],stack[N<<1],n,m,x,y,top,cnt; bool vis[N<<1]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline bool read(int &x) { x=0; char ch; while (!isdigit(ch=tc())) if (ch==EOF) return 0; while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); return 1; } inline void add(int x,int y) { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } inline bool DFS(int now) { if (vis[now^1]) return 0; if (vis[now]) return 1; vis[now]=1; stack[top++]=now; for (register int i=head[now];~i;i=e[i].next) if (!DFS(e[i].to)) return 0; return 1; } inline bool solve(void) { for (register int i=0;i<(n<<1);i+=2) if (!vis[i]&&!vis[i^1]) { top=0; if (!DFS(i)) { while (top) vis[stack[--top]]=0; if (!DFS(i^1)) return 0; } } return 1; } inline void print(void) { for (register int i=0;i<(n<<1);i+=2) printf("%d\n",vis[i]?i+1:(i^1)+1); } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; while (read(n)&&read(m)) { memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); for (cnt=0,i=1;i<=m;++i) { read(x); read(y); --x; --y; add(x,y^1); add(y,x^1); } if (solve()) print(); else puts("NIE"); } return 0; }