二分+2-Sat
判断是否可行
输出字典序最小的解
输出字典序可行解
其实这些都是小问题,最重要的是建图,请看论文。
特殊的建边方式,如果a b是一对,a必须选,那么就是b->a建边。
模板题
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> using namespace std; #define LL long long struct node { int u,v,next; }edge[2001*1001]; int t,scnt,top; int first[2001]; int DFN[2001]; int Low[2001]; int Belong[2001]; int in[2001],stack[2001]; void CL() { t = top = scnt = 0; memset(first,-1,sizeof(first)); memset(DFN,0,sizeof(DFN)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } void Tarjan(int u) { int v,i; DFN[u] = Low[u] = ++ t; in[u] = 1; stack[top++] = u; for(i = first[u];i != -1;i = edge[i].next) { v = edge[i].v; if(!DFN[v]) { Tarjan(v); if(Low[u] > Low[v]) { Low[u] = Low[v]; } } else if(in[v] && Low[u] > DFN[v]) { Low[u] = DFN[v]; } } if(DFN[u] == Low[u]) { scnt ++; do { v = stack[--top]; in[v] = 0; Belong[v] = scnt; }while(u != v); } } int main() { int n,m,a1,a2,c1,c2,i,u,v; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 0;i < m;i ++) { scanf("%d%d%d%d",&a1,&a2,&c1,&c2); u = a1*2+c1; v = a2*2+c2; add(u,v^1); add(v,u^1); } for(i = 0;i < 2*n;i ++) { if(!DFN[i]) { Tarjan(i); } } for(i = 0;i < n;i ++) { if(Belong[2*i] == Belong[2*i+1]) break; } if(i == n) printf("YES\n"); else printf("NO\n"); } return 0; }
论文上的例题,输出字典序。
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> using namespace std; #define LL long long #define N 8001 int que[2*N]; int flag[2*N]; int first[2*N]; int t,n,num; struct node { int u,v,next; }edge[60001]; void CL() { t = 1; memset(first,-1,sizeof(first)); memset(flag,0,sizeof(flag)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } int dfs(int x) { int i,v; if(flag[x] == 1) return 1; else if(flag[x] == 2) return 0; flag[x] = 1; flag[x^1] = 2; que[num++] = x; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(!dfs(v)) return 0; } return 1; } int judge() { int i,j; for(i = 0;i < 2*n;i ++) { if(flag[i]) continue; num = 0; if(!dfs(i)) { for(j = 0;j < num;j ++) { flag[que[j]] = 0; flag[que[j]^1] = 0; } if(!dfs(i^1)) return 0; } } return 1; } int main() { int m,u,v,i; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 0;i < m;i ++) { scanf("%d%d",&u,&v); u --; v --; add(u,v^1); add(v,u^1); } if(judge()) { for(i = 0;i < 2*n;i ++) { if(flag[i] == 1) printf("%d\n",i+1); } } else { printf("NIE\n"); } } return 0; }
输出可行解。
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <queue> #include <algorithm> using namespace std; #define LL long long struct node { int u,v,next; }edge[100001],g[100001]; int t,scnt,top,T; int first[2001]; int DFN[2001]; int op[2001]; int Low[2001]; int Belong[2001]; int in[2001],stack[2001]; int input[2001]; int flag[2001]; void CL() { T = t = top = scnt = 0; memset(first,-1,sizeof(first)); memset(DFN,0,sizeof(DFN)); memset(flag,0,sizeof(flag)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } void _add(int u,int v) { g[T].u = u; g[T].v = v; g[T].next = first[u]; first[u] = T ++; } void Tarjan(int u) { int v,i; DFN[u] = Low[u] = ++ t; in[u] = 1; stack[top++] = u; for(i = first[u];i != -1;i = edge[i].next) { v = edge[i].v; if(!DFN[v]) { Tarjan(v); if(Low[u] > Low[v]) { Low[u] = Low[v]; } } else if(in[v] && Low[u] > DFN[v]) { Low[u] = DFN[v]; } } if(DFN[u] == Low[u]) { scnt ++; do { v = stack[--top]; in[v] = 0; Belong[v] = scnt; }while(u != v); } } void tpsort() { queue<int> que; memset(first,-1,sizeof(first)); int i,v,u; for(i = 0;i < t;i ++) { u = Belong[edge[i].u]; v = Belong[edge[i].v]; if(u != v) { _add(v,u); input[u] ++; } } for(i = 1;i <= scnt;i ++) { if(input[i] == 0) que.push(i); } while(!que.empty()) { u = que.front(); que.pop(); if(flag[u] == 0) { flag[u] = 1; flag[op[u]] = 2; } for(i = first[u];i != -1;i = g[i].next) { v = g[i].v; if(--input[v] == 0) que.push(v); } } } int main() { int n,m,i,u,v; char s1,s2; while(scanf("%d%d%*c",&n,&m)!=EOF) { if(n == 0&&m == 0) break; CL(); for(i = 0;i < m;i ++) { scanf("%d%c%*c%d%c%*c",&u,&s1,&v,&s2); if(s1 == 'w') u = u*2; else u = u*2 + 1; if(s2 == 'w') v = v*2; else v = v*2 + 1; if(u != (v^1)) { add(u,v^1); add(v,u^1); } } add(0,1); for(i = 0;i < 2*n;i ++) { if(!DFN[i]) { Tarjan(i); } } for(i = 0;i < n;i ++) { if(Belong[2*i] == Belong[2*i+1]) break; op[Belong[2*i]] = Belong[2*i+1]; op[Belong[2*i+1]] = Belong[2*i]; } if(i != n) { printf("bad luck\n"); continue; } tpsort(); int z = 0; for(i = 0; i < 2*n; i++) { if(flag[Belong[i]] == 1 && i != 1) { if(z) printf(" "); z = 1; printf("%d", i/2); if(i%2 == 0) printf("h"); else printf("w"); } } printf("\n"); } return 0; }