《由对称性解2-SAT问题》:http://wenku.baidu.com/view/afd6c436a32d7375a41780f2.html
所谓2-sat问题,就是在满足一定逻辑条件下,是否存在可行解的问题,这里的“可行”指的是在逻辑上不出现矛盾。具体参见上述ppt,确实是非常不错的讲解。
问题类型:
通常来说,一般是有若干个组,每一个组有两个元素,A和A',二者只能选择一个。同时还有一些逻辑关系,比如A和B不能同时存在,B不能和C存在等。问题是,是否存在从每个组中选出一个元素,使得所选的元素满足两两相容。
问题解决方法:
构图:比如A和B不能存在,B和C'不能同时存在,那么选择A的话,则必选B',同时,若选了B,则必定要选A'。同理若选择了B,则必须选C,选则了C'则必须选B'。可以得到其中的对称关系。这里的构图方式是,对于A和B不能共存,则A-B',B-A'...
缩点:对于构成的图,用强连通的tarjan算法进行缩点,如果对于任意X和X',如果他们在同一个环中,说明没有解(因为在同一个组中的元素,二者只能出现一个)。
输出可行解:若存在解,将缩点后的图上的边反向,然后进行拓扑排序。
这两道题不需要输出可行解,故直接构图缩点判断即可:
HDU3602:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <algorithm>
#define SIZE 2010
using namespace std;
struct node
{
int to,next;
}edge[SIZE*SIZE];
int head[SIZE],idx;
int n,m;
int dfsn[SIZE],low[SIZE],tim;
int be[SIZE],num;
stack <int> sta;
bool instack[SIZE];
void addnode(int from,int to)
{
edge[idx].to = to;
edge[idx].next = head[from];
head[from] = idx++;
}
void tarjan(int cur)
{
dfsn[cur] = low[cur] = ++tim;
sta.push(cur);
instack[cur] = true;
for(int i=head[cur]; i!=-1; i=edge[i].next)
{
int to = edge[i].to;
if(!dfsn[to])
{
tarjan(to);
low[cur] = min(low[cur],low[to]);
}
else if(instack[to])
low[cur] = min(low[cur],dfsn[to]);
}
if(dfsn[cur] == low[cur])
{
int tem = -1;
++num;
while(tem != cur)
{
tem = sta.top();
sta.pop();
instack[tem] = false;
be[tem] = num;
}
}
}
void solve()
{
memset(dfsn,0,sizeof(dfsn));
memset(low,0,sizeof(low));
memset(instack,0,sizeof(instack));
memset(be,0,sizeof(be));
while(!sta.empty()) sta.pop();
tim = num = 0;
for(int i=0; i<2*n; i++)
if(!dfsn[i])
tarjan(i);
bool ans = true;
for(int i=0; i<2*n; i+=2)
if(be[i] == be[i+n]){
ans = false;
break;
}
if(ans) puts("YES");
else puts("NO");
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
idx = 0;
memset(head,-1,sizeof(head));
int x,y,sex1,sex2;
for(int i=1; i<=m; i++)
{
scanf("%d%d%d%d",&x,&y,&sex1,&sex2);
if(sex1 && sex2)
{
addnode(x+n,y);
addnode(y+n,x);
}
if(!sex1 && sex2)
{
addnode(x,y);
addnode(y+n,x+n);
}
if(sex1 && !sex2)
{
addnode(x+n,y+n);
addnode(y,x);
}
if(!sex1 && !sex2)
{
addnode(x,y+n);
addnode(y,x+n);
}
}
solve();
}
return 0;
}
HDU1824:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <algorithm>
#define SIZE 2020
using namespace std;
struct node
{
int to,next;
}edge[SIZE*10];
int head[SIZE],idx;
int n,m;
int pos[SIZE];
int dfsn[SIZE],low[SIZE],tim;
int be[SIZE],num;
bool instack[SIZE];
stack <int> sta;
void addnode(int from,int to)
{
edge[idx].to = to;
edge[idx].next = head[from];
head[from] = idx++;
}
void tarjan(int cur)
{
dfsn[cur] = low[cur] = ++tim;
sta.push(cur);
instack[cur] = true;
for(int i=head[cur]; i!=-1; i=edge[i].next)
{
int to = edge[i].to;
if(!dfsn[to])
{
tarjan(to);
low[cur] = min(low[cur],low[to]);
}
else if(instack[to])
low[cur] = min(low[cur],dfsn[to]);
}
if(dfsn[cur] == low[cur])
{
int tem = -1;
++num;
while(tem != cur)
{
tem = sta.top();
sta.pop();
instack[tem] = false;
be[tem] = num;
}
}
}
void solve()
{
memset(dfsn,0,sizeof(dfsn));
memset(low,0,sizeof(low));
memset(be,0,sizeof(be));
memset(instack,0,sizeof(instack));
while(!sta.empty()) sta.pop();
tim = num = 0;
for(int i=0; i<2*n; i++)
if(!dfsn[i])
tarjan(i);
bool ans = true;
for(int i=0; i<2*n; i++)
if(be[i] == be[i+n]){
ans = false;
break;
}
if(ans) puts("yes");
else puts("no");
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int x,y,z;
for(int i=0; i<n; i++)
{
scanf("%d%d%d",&x,&y,&z);
pos[x] = i;
pos[y] = pos[z] = i+n;
}
idx = 0;
memset(head,-1,sizeof(head));
for(int i=1; i<=m; i++)
{
scanf("%d%d",&x,&y);
if(pos[y] >= n)
addnode(pos[x],pos[y]-n);
else
addnode(pos[x],pos[y]+n);
if(pos[x] >= n)
addnode(pos[y],pos[x]-n);
else
addnode(pos[y],pos[x]+n);
}
solve();
}
return 0;
}