HDU 1848 2SAT 输出字典序最小
告诉你两两冲突的序列,让输出字典序最小。
一开始老老实实tarjan,写完了发现后面完全不能好弄,因为选了第一个点,你没办法快速找出全部对立组,只能找出本来在一个pair中的那个对立组,而找不出给定的那个随意的对立组。所以直接从1开始染色,弄不出来就染2。以此类推。
这个题还有一个教训就是,点要多开一倍,边也要多开一倍。老是忘。。。
#include<algorithm> #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<stack> #include<cmath> #include<cstdlib> using namespace std; const int MAXN=16010; struct node { int v; int nxt; }; node edge[40100];//边数 int head[MAXN]; int clo[MAXN]; int dirty[MAXN],dirtop=0; int n,m; int cnt=0; void add_edge(int u,int v) { edge[cnt].v=v; edge[cnt].nxt=head[u]; head[u]=cnt; cnt++; } int dfs(int u) { clo[u]=1; clo[u^1]=2; dirty[dirtop++]=u; for (int i=head[u];i!=-1;i=edge[i].nxt) { int v=edge[i].v; if (clo[v]==1) continue; if (clo[v]==2||!dfs(v)) return 0; } } int solve() { memset(clo,0,sizeof(clo)); for (int i=0; i<2*n; i+=2) { if (!clo[i]) { dirtop=0; if (!dfs(i)) { for (int i=0;i<dirtop;i++) clo[dirty[i]]=clo[dirty[i]^1]=0; if (!dfs(i+1)) return 0; } } } return 1; } int main() { while (scanf ("%d%d",&n,&m)!=EOF) { cnt=0; memset(head,-1,sizeof(head)); while (m--) { int t1,t2; scanf ("%d%d",&t1,&t2); --t1,--t2; add_edge(t1,t2^1); add_edge(t2,t1^1); } if (!solve()) printf ("NIE\n"); else { for (int i=0;i<2*n;i++) { if (clo[i]==1) { printf ("%d\n",i+1); } } } } return 0; }