POJ 3207/ POJ 3678 【2-SAT】


POJ 3207 Ikki's Story IV - Panda's Trick
大意:已知圆上均匀分布着n个点,编号按逆时针数分别为0,1,2,。。。n-1
由上述点够成m条边,这些边可分布于圆内或圆外,问这些边有没有可能不相交?

分析:
2-SAT
1.构图:
   每条边可在圆内或圆外,对应于两个点,Ai,Ai'
2.若边i与边j相交,
 a.若选择Ai边则必须选Aj'边,
 b.若选择Ai'边则必须选择Aj边,
 故对应于上图:
  建立边(Ai,Aj'),(Ai',Aj)
3.若存在边i,有Ai,Ai'属于同一个强连通分量,则一定会相交

View Code
1 #include < stdio.h >
2 #include < string .h >
3   const int N = 500 + 10 ;
4 #include < vector >
5   using namespace std;
6 vector < int > edge[N * 2 ]; // 正向边
7 vector < int > iedge[N * 2 ]; // 逆向边
8 struct Link
9 {
10 int a,b;
11 }link[N];
12
13 inline void addEdge( int s, int t)
14 {
15 edge[s].push_back(t);
16 iedge[t].push_back(s);
17 }
18 // 判断两线段是否相交
19 inline bool isconnect(Link A,Link B)
20 {
21 if (A.a < B.a && B.a < A.b && A.b < B.b)
22 return true ;
23 if (B.a < A.a && A.a < B.b && B.b < A.b)
24 return true ;
25 return false ;
26 }
27
28 bool visited[N * 2 ];
29 int color[N * 2 ]; // color[i]标记i点所属分量
30 vector < int > stack; // 记录拓扑排序时的栈
31
32 void dfs1( int p) // dfs1实际是在求拓扑图,拓扑排序后的信息逆序存于statck中
33 {
34 if (visited[p] == true ) return ;
35 visited[p] = true ;
36 int sz = edge[p].size();
37 int i;
38 for (i = 0 ;i < sz;i ++ )
39 {
40 if ( ! visited[edge[p][i]])
41 dfs1(edge[p][i]);
42 }
43
44 stack.push_back(p);
45 }
46
47 void dfs2( int n, int group)
48 {
49 if (visited[n] == true ) return ;
50 visited[n] = true ;
51 int i,sz = iedge[n].size();
52 for (i = 0 ;i < sz;i ++ )
53 {
54 if ( ! visited[iedge[n][i]])
55 dfs2(iedge[n][i],group);
56 }
57 color[n] = group;
58 }
59 void two_SAT( int n) // n为点的个数
60 {
61 memset(visited, false , sizeof (visited));
62 int i,j;
63 stack.clear();
64 for (i = 0 ;i < n;i ++ )
65 {
66 if ( ! visited[i])dfs1(i);
67 }
68
69 memset(visited, false , sizeof (visited));
70
71 int group = 0 ;
72 int sz = stack.size();
73 for (i = sz - 1 ;i >= 0 ;i -- )
74 {
75 if ( ! visited[i])
76 dfs2(i,group ++ );
77 }
78
79 }
80
81 // 判断Ai,Ai'是否属于同一个强连通分量
82 bool check( int m)
83 {
84 for ( int i = 0 ;i < m;i ++ )
85 if (color[i] == color[i + m]) return false ;
86 return true ;
87 }
88
89 int main()
90 {
91 int n,m;
92 while (scanf( " %d%d " , & n, & m) != EOF)
93 {
94 int i,j;
95 for (i = 0 ;i < 2 * m + 1 ;i ++ )
96 {
97 edge[i].clear();
98 iedge[i].clear();
99 }
100 for (i = 0 ;i < m;i ++ )
101 {
102 scanf( " %d%d " , & link[i].a, & link[i].b);
103 if (link[i].a > link[i].b)
104 {
105 int temp = link[i].a;
106 link[i].a = link[i].b;
107 link[i].b = temp;
108 }
109 }
110
111 for (i = 0 ;i < m;i ++ )
112 for (j = i + 1 ;j < m;j ++ )
113 {
114 if (isconnect(link[i],link[j]))
115 {
116 addEdge(i,j + m);
117 addEdge(j + m,i);
118 addEdge(i + m,j);
119 addEdge(j,i + m);
120 }
121 }
122
123 two_SAT( 2 * m);
124
125 if (check(m))
126 printf( " panda is telling the truth...\n " );
127 else
128 printf( " the evil panda is lying again\n " );
129
130 }
131
132 return 0 ;
133 }

  POJ 3678 Katu Puzzle
   http://poj.org/problem?id=3678
大意:有n个点,每个点的权值Xi为0或1,满足以下m个条件:
每个条件的格式如:
  Xa op Xb = c
 其中op为and,or,xor运算中的一种

问是否存在满足上述条件的图?

分析:
构图,对于每个节点,可取0或1,分别对应于xa,xa+n
那么:
1.若Xa or Xb = 1
   a.若Xa=0必有Xb=1,故建边Xa->Xb+n
   b.若Xb=0必有Xa=1,建边 Xb->Xa+n
2.若Xa or Xb = 0
   a.必有Xa,Xb均为0,即添边Xa->Xb,xb->xa
   b. Xa 或者Xb=0均非法,即添边xa+n->xa,xb+n->xb

3.若Xa and Xb = 1
   a.必有xa,xb均为1,故建边xa+n->xb+n,xb+n->xa+n
   b.xa=0或xb=0非法,建边xa->xa+n,xb->xb+n

4.若Xa and Xb =0
   a.若Xa = 1必有Xb = 0 即建边xa+n->xb
   b.若Xb = 1必有Xa = 0 即建边xb+n->xa

5.若Xa xor Xb= 1
   a.xa+n -> xb
   b.xb -> xa+n
   c.xb+n -> xa
   d.xa ->xb+n  
6.若Xa xor Xb = 0
   a.xa->xb
   b.xb->xa
   c.xa+n->xb+n
   d.xb+n->xa+n

 

View Code
1 #include < stdio.h >
2 #include < string .h >
3 const int N = 1000 + 10 ;
4 #include < vector >
5 using namespace std;
6 vector < int > edge[N * 2 ]; // 正向边
7 vector < int > iedge[N * 2 ]; // 逆向边
8
9 inline void addEdge( int s, int t)
10 {
11 edge[s].push_back(t);
12 iedge[t].push_back(s);
13 }
14
15 bool visited[N * 2 ];
16 int color[N * 2 ]; // color[i]标记i点所属分量
17 vector < int > stack; // 记录拓扑排序时的栈
18 void dfs1( int p) // dfs1实际是在求拓扑图,拓扑排序后的信息逆序存于statck中
19 {
20 if (visited[p] == true ) return ;
21 visited[p] = true ;
22 int sz = edge[p].size();
23 int i;
24 for (i = 0 ;i < sz;i ++ )
25 {
26 if ( ! visited[edge[p][i]])
27 dfs1(edge[p][i]);
28 }
29
30 stack.push_back(p);
31 }
32
33 void dfs2( int n, int group)
34 {
35 if (visited[n] == true ) return ;
36 visited[n] = true ;
37 int i,sz = iedge[n].size();
38 for (i = 0 ;i < sz;i ++ )
39 {
40 if ( ! visited[iedge[n][i]])
41 dfs2(iedge[n][i],group);
42 }
43 color[n] = group;
44 }
45 void two_SAT( int n) // n为点的个数
46 {
47 memset(visited, false , sizeof (visited));
48 int i;
49 stack.clear();
50 for (i = 0 ;i < n;i ++ )
51 {
52 if ( ! visited[i])dfs1(i);
53 }
54
55 memset(visited, false , sizeof (visited));
56
57 int group = 0 ;
58 int sz = stack.size();
59 for (i = sz - 1 ;i >= 0 ;i -- )
60 {
61 if ( ! visited[stack[i]])
62 dfs2(stack[i],group ++ );
63 }
64
65 // printf("group = %d \n",group);
66
67 }
68
69 // 判断Ai,Ai'是否属于同一个强连通分量
70 bool check( int m)
71 {
72 for ( int i = 0 ;i < m;i ++ )
73 if (color[i] == color[i + m]) return false ;
74 return true ;
75 }
76
77 void processAnd( int a, int b, int c, int n) // 处理processAnd
78 {
79 if (c == 0 ) // a,b不能同时取1
80 {
81 addEdge(a + n,b); // a=1 =>b=0
82 addEdge(b + n,a); // b=1 =>a=0
83 } else
84 {
85 addEdge(a,a + n); // a = 0必不合法
86 addEdge(b,b + n); // b = 0必不合法
87 addEdge(a + n,b + n);
88 addEdge(b + n,a + n);
89 }
90 }
91
92 void ProcessOr( int a, int b, int c, int n)
93 {
94 if (c == 0 )
95 {
96 addEdge(a + n,a); // a=1必不合法
97 addEdge(b + n,b); // b=1必不合法
98 addEdge(a,b);
99 addEdge(b,a);
100 }
101 else
102 {
103 addEdge(a,b + n); // a=0 => b = 1
104 addEdge(b,a + n); // b=0 => a = 1
105 }
106 }
107
108 inline void Processxor( int a, int b, int c, int n)
109 {
110 if (c == 1 )
111 {
112 addEdge(a,b + n);
113 addEdge(b + n,a);
114 addEdge(a + n,b);
115 addEdge(b,a + n);
116 }
117 else
118 {
119 addEdge(a + n,b + n);
120 addEdge(b + n,a + n);
121 addEdge(a,b);
122 addEdge(b,a);
123 }
124 }
125 int main()
126 {
127 int n,m;
128 int a,b,c;
129 char op[ 10 ];
130
131 while (scanf( " %d%d " , & n, & m) != EOF)
132 {
133 int i;
134 for (i = 0 ;i < 2 * n + 1 ;i ++ )
135 {
136 edge[i].clear();
137 iedge[i].clear();
138 }
139 while (m -- )
140 {
141
142 scanf( " %d%d%d%s " , & a, & b, & c,op);
143 if (op[ 0 ] == ' A ' )
144 processAnd(a,b,c,n);
145 else
146 if (op[ 0 ] == ' O ' )
147 ProcessOr(a,b,c,n);
148 else
149 if (op[ 0 ] == ' X ' )
150 Processxor(a,b,c,n);
151
152 }
153
154 two_SAT( 2 * n);
155
156 if (check(n))
157 printf( " YES\n " );
158 else
159 printf( " NO\n " );
160
161 }
162
163 return 0 ;
164 }

你可能感兴趣的:(poj)