HDU3062(2-SAT+暴力+scc)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3062

题目意思:有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。n 个人同时列席是否有解。

题目思路:暴力法走一遍,如果solve成功则可以;也可以tarjan缩点,用定理。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 2005;
 4 const int M = N*N;
 5 struct Edge{
 6     int v,next;
 7 }edge[M];
 8 int head[N],sta[N],cnt,top;
 9 bool vis[N];
10 void init()
11 {
12     memset(head,-1,sizeof(head));
13     memset(vis,false,sizeof(vis));
14     memset(sta,0,sizeof(sta));
15     cnt = top = 0;
16 }
17 void inline add(int u,int v)
18 {
19     edge[++cnt].v = v;
20     edge[cnt].next = head[u];
21     head[u] = cnt; 
22 }
23 bool dfs(int u)
24 {
25     if(vis[u^1]) return false;
26     if(vis[u]) return true;
27     vis[u] = true;
28     sta[top++] = u;
29     for(int i = head[u];i != -1;i = edge[i].next)
30     {
31         if(!dfs(edge[i].v)) return false;
32     }
33     return true;
34 }
35 bool solve(int n)
36 {
37     for(int i = 0;i < (n<<1);i += 2)
38     {
39         if(!vis[i]&&!vis[i^1])
40         {
41             top = 0;
42             if(!dfs(i))
43             {
44                 while(top) vis[sta[--top]] = false;
45                 if(!dfs(i^1)) return false;
46             }
47         }
48     }
49     return true;
50 }
51 int main()
52 {
53     int n,m;
54     while(~scanf("%d%d",&n,&m))
55     {
56         init();
57         for(int i = 1;i <= m; i++)
58         {
59             int a1,a2,c1,c2;
60             scanf("%d%d%d%d",&a1,&a2,&c1,&c2);
61             if(c1 == 0) a1 = (a1<<1);
62             else a1 = (a1<<1) + 1;
63             if(c2 == 0) a2 = (a2<<1);
64             else a2 = (a2<<1) + 1;
65             add(a1^1,a2);
66             add(a2^1,a1);
67         }
68         if(solve(n)) printf("YES\n");
69         else printf("NO\n");
70     }
71     return 0;
72 } 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using std::min;
 5 const int N = 2010, M = N * N;
 6 struct Edge
 7 {
 8     int to, nex;
 9 } edge[M];
10 int num_e;
11 int head[N];
12 int dfn[N], low[N], scc[N], sz[N], idx, tot;
13 bool insta[N];
14 int sta[N], top;
15 void init() {
16     num_e = 0, top = 0, idx = 0, tot = 0;
17     memset(head, 0, sizeof(head));
18     memset(insta, 0, sizeof(insta));
19     memset(scc, 0, sizeof(scc));
20     memset(dfn, 0, sizeof(dfn));
21 }
22 void add_edge(int x, int y) {
23     edge[++num_e].to = y;
24     edge[num_e].nex = head[x];
25     head[x] = num_e;
26 }
27 void tarjan(int u) {
28     dfn[u] = low[u] = ++idx;
29     sta[++top] = u;
30     insta[u] = true;
31     for (int i = head[u]; i; i = edge[i].nex) {
32         int v = edge[i].to;
33         if (!dfn[v]) {
34             tarjan(v);
35             low[u] = min(low[u], low[v]);
36         }
37         else if (insta[v]) low[u] = min(low[u], dfn[v]);
38     }
39     if (dfn[u] == low[u]) {
40         ++tot;
41         do {
42             scc[sta[top]] = tot;
43             sz[tot]++;
44             insta[sta[top]] = false;
45         } while (sta[top--] != u);
46     }
47 }
48 
49 int main() {
50     int n, m;
51     while (~scanf("%d %d", &n, &m)) {
52         init();
53         for (int i = 0, a1, a2, c1, c2; i < m; i++) {
54             scanf("%d %d %d %d", &a1, &a2, &c1, &c2);
55             add_edge(2 * a1 + c1, 2 * a2 + 1 - c2);
56             add_edge(2 * a2 + c2, 2 * a1 + 1 - c1);
57         }
58         for (int i = 0; i < 2 * n; i++) {
59             if (!dfn[i]) tarjan(i);
60         }
61         bool ans = true;
62         for (int i = 0; i < 2 * n; i += 2) {
63             if (scc[i] == scc[i+1]) {
64                 ans = false;
65                 break;
66             }
67         }
68         printf("%s\n", ans ? "YES" : "NO");
69     }
70     return 0;
71 }

 

上一篇:STA树的深度(树型DP)


下一篇:USART1_IRQHandler 函数的理解