HDU 3062 Party(2-SAT模版题)

Problem Description
有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?
 
Input
n: 表示有n对夫妻被邀请 (n<= 1000)
m: 表示有m 对矛盾关系 ( m < (n - 1) * (n -1))

在接下来的m行中,每行会有4个数字,分别是 A1,A2,C1,C2 
A1,A2分别表示是夫妻的编号 
C1,C2 表示是妻子还是丈夫 ,0表示妻子 ,1是丈夫
夫妻编号从 0 到 n -1 
 
Output
如果存在一种情况 则输出YES 
否则输出 NO
 
思路:2-SAT模版题,分别要求夫妻必上一个、仇人不能同时上
 
两个代码,第一个是普通的搜索,第二个是tarjan的解法,第一个593MS,第二个625MS(难道写挫了。。。?),(好吧用改一下第二个代码用C++交变成了312MS……)
 
 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 const int MAXN = 4010;
 6 const int MAXM = 1010*1010*3;
 7 
 8 struct TwoSAT{
 9     int n, ecnt;
10     bool mark[MAXN];
11     int St[MAXN], c;//手动栈
12     int head[MAXN];
13     int next[MAXM], to[MAXM];
14 
15     bool dfs(int x){
16         if(mark[x^1]) return false;
17         if(mark[x]) return true;
18         mark[x] = true;
19         St[c++] = x;
20         for(int p = head[x]; p; p = next[p])
21             if(!dfs(to[p])) return false;
22         return true;
23     }
24 
25     void init(int n){
26         this->n = n;
27         ecnt = 2;
28         memset(head,0,sizeof(head));
29         memset(mark,0,sizeof(mark));
30     }
31 
32     void addEdge1(int x, int y){//x*y=false
33         to[ecnt] = y^1; next[ecnt] = head[x]; head[x] = ecnt++;
34         to[ecnt] = x^1; next[ecnt] = head[y]; head[y] = ecnt++;
35     }
36 
37     void addEdge2(int x, int y){//x+y=true
38         to[ecnt] = y; next[ecnt] = head[x^1]; head[x^1] = ecnt++;
39         to[ecnt] = x; next[ecnt] = head[y^1]; head[y^1] = ecnt++;
40     }
41 
42     bool solve(){
43         for(int i = 0; i < n*2; i += 2)
44             if(!mark[i] && !mark[i+1]){
45                 c = 0;
46                 if(!dfs(i)) {
47                     while(c>0) mark[St[--c]] = false;
48                     if(!dfs(i^1)) return false;
49                 }
50             }
51         return true;
52     }
53 } G;
54 
55 int main(){
56     int n, m, a, b, c, d;
57     while(scanf("%d%d",&n,&m)!=EOF){
58         G.init(n);
59         for(int i = 0; i < n; ++i) G.addEdge2(i*2,(i+n)*2);
60         while(m--){
61             scanf("%d%d%d%d",&a,&b,&c,&d);
62             G.addEdge1((a + n*c)*2, (b + n*d)*2);
63         }
64         if(G.solve()) printf("YES\n");
65         else printf("NO\n");
66     }
67     return 0;
68 }
View Code

 

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 const int MAXN = 2010;
 6 const int MAXM = 1010*1010*2;
 7 
 8 struct TwoSAT{
 9     int n, ecnt, dfs_clock, scc_cnt;
10     int St[MAXN], c;//手动栈
11     int head[MAXN], lowlink[MAXN], pre[MAXN], sccno[MAXN];
12     int next[MAXM], to[MAXM];
13 
14     void dfs(int u){
15         pre[u] = lowlink[u] = ++dfs_clock;
16         St[++c] = u;
17         for(int p = head[u]; p; p = next[p]){
18             int &v = to[p];
19             if(!pre[v]){
20                 dfs(v);
21                 if(lowlink[u] > lowlink[v]) lowlink[u] = lowlink[v];
22             }else if(!sccno[v]){
23                 if(lowlink[u] > pre[v]) lowlink[u] = pre[v];
24             }
25         }
26         if(lowlink[u] == pre[u]){
27             scc_cnt++;
28             while(true){
29                 int x = St[c--];
30                 sccno[x] = scc_cnt;
31                 if(x == u) break;
32             }
33         }
34     }
35 
36     void init(int n){
37         this->n = n;
38         ecnt = 2; dfs_clock = scc_cnt = 0;
39         memset(head,0,sizeof(head));
40         memset(sccno,0,sizeof(sccno));
41         memset(pre,0,sizeof(pre));
42     }
43 
44     void addEdge1(int x, int y){//x*y=false
45         to[ecnt] = y^1; next[ecnt] = head[x]; head[x] = ecnt++;
46         to[ecnt] = x^1; next[ecnt] = head[y]; head[y] = ecnt++;
47     }
48 
49     bool solve(){
50         for(int i = 0; i < n; ++i)
51             if(!pre[i]) dfs(i);
52         for(int i = 0; i < n; i += 2)
53             if(sccno[i] == sccno[i^1]) return false;
54         return true;
55     }
56 } G;
57 
58 int main(){
59     int n, m, a, b, c, d;
60     while(scanf("%d%d",&n,&m)!=EOF){
61         G.init(2*n);
62         while(m--){
63             scanf("%d%d%d%d",&a,&b,&c,&d);
64             G.addEdge1(a*2 + c, b*2 + d);
65         }
66         if(G.solve()) printf("YES\n");
67         else printf("NO\n");
68     }
69     return 0;
70 }
tarjan

 

posted @ 2013-07-07 20:25  Oyking  阅读(413)  评论(0编辑  收藏  举报