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  constint N =500+10;
4 #include<vector>
5  usingnamespace 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 returntrue;
23 if(B.a<A.a&&A.a<B.b&&B.b<A.b)
24 returntrue;
25 returnfalse;
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])returnfalse;
86 returntrue;
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 return0;
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 constint N =1000+10;
4 #include<vector>
5 usingnamespace 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])returnfalse;
74 returntrue;
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 return0;
164 }
posted @ 2011-03-19 12:15  AndreMouche  阅读(533)  评论(0编辑  收藏  举报