[POI2001]Peaceful Commission

题目大意:
  有n个国家要派代表开会,每个国家有两个代表可供选择。
  有m对代表有仇,不能同时开会。
  若每个国家只能派一个代表开会,问是否存在一种方案,使得每个国家都能正常参会?
  如果有,输出字典序最小的一种。

思路:
  2-SAT经典模型。
  如果两个代表之间有仇,那么就给其中一个代表a连一条通向另一国家另一代表b的有向边,表示选a后一定要选b。
  判定时就用Tarjan缩点,如果同一国家两个代表在同一个强连通分量中,那么说明两个代表必须同时参加或不参加,这是不合法的。
  构造字典序最小的方案时,可以从小到大枚举每一个代表,然后DFS选定该代表后,必须选的其它代表,如果必须选的的代表和已选代表矛盾,则不加入。

 1 #include<stack>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<vector>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int N=16000;
13 std::stack<int> s;
14 std::vector<int> e[N<<1];
15 bool ins[N<<1],select[N<<1];
16 int dfn[N<<1],low[N<<1],scc[N<<1],cnt,id;
17 inline void add_edge(const int &u,const int &v) {
18     e[u].push_back(v);
19 }
20 void tarjan(const int &x) {
21     s.push(x);
22     ins[x]=true;
23     dfn[x]=low[x]=++cnt;
24     for(unsigned i=0;i<e[x].size();i++) {
25         const int &y=e[x][i];
26         if(!dfn[y]) {
27             tarjan(y);
28             low[x]=std::min(low[x],low[y]);
29         } else if(ins[y]) {
30             low[x]=std::min(low[x],dfn[y]);
31         }
32     }
33     if(low[x]==dfn[x]) {
34         id++;
35         int y=-1;
36         while(y!=x) {
37             y=s.top();
38             s.pop();
39             ins[y]=false;
40             scc[y]=id;
41         }
42     }
43 }
44 bool dfs(const int &x) {
45     if(select[x^1]) return false;
46     s.push(x);
47     select[x]=true;
48     for(unsigned i=0;i<e[x].size();i++) {
49         const int &y=e[x][i];
50         if(select[y]) continue;
51         if(!dfs(y)) return false;
52     }
53     return true;
54 }
55 inline void reset(const int &n) {
56     cnt=id=0;
57     for(register int i=0;i<n<<1;i++) {
58         dfn[i]=low[i]=select[i]=0;
59         e[i].clear();
60     }
61 }
62 int main() {
63     int n,m;
64     while(~scanf("%d%d",&n,&m)) {
65         while(m--) {
66             const int u=getint()-1,v=getint()-1;
67             add_edge(u,v^1);
68             add_edge(v,u^1);
69         }
70         for(register int i=0;i<n<<1;i++) {
71             if(!dfn[i]) tarjan(i);
72         }
73         for(register int i=0;i<n;i++) {
74             if(scc[i<<1]==scc[i<<1|1]) {
75                 puts("NIE");
76                 goto Next;
77             }
78         }
79         for(register int i=0;i<n<<1;i++) {
80             if(!select[i]&&!select[i^1]) {
81                 if(dfs(i)) {
82                     while(!s.empty()) s.pop();
83                 } else {
84                     while(!s.empty()) {
85                         const int x=s.top();
86                         s.pop();
87                         select[x]=false;
88                     }
89                 }
90             }
91         }
92         for(register int i=0;i<n<<1;i++) {
93             if(select[i]) printf("%d
",i+1);
94         }
95         Next:
96             reset(n);
97     }
98     return 0;
99 }
原文地址:https://www.cnblogs.com/skylee03/p/8183281.html