题意:中文的,不解释了

思路:2-sat基本题,练习的第一道题目,网上找了个模板

话说这个vector< vector<int> >还真是弄了好久的,所以先

写了一个一维的弄了好久好久……2-sat终于有点思路了,各种错啊……

这个是一维的:

#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include <cstdio>
#include<algorithm>
#include <cstring>
using namespace std;

const int N=2005;

vector<int>map1[N];
vector<int>map2[N];

bool used[N],flag[N][N];

int order[N],id[N];
int m,n,cnt,color;

void Init()
{
for(int i=0;i<2*n;i++)
{
map1[i].clear();
map2[i].clear();
}
}

void addedge(int from,int to)
{
map1[from].push_back(to);
map2[to].push_back(from);
}

void build_map1()
{
int i,x,y,u,v,uu,vv;
for(i=0;i<m;i++)
{
scanf("%d%d%d%d",&x,&y,&u,&v);
u=2*x+u;
uu=(u%2)?u-1:u+1;
v=2*y+v;
vv=(v%2)?v-1:v+1;
addedge(u,vv);
addedge(v,uu);
}
}

void dfs1(int u) //把所有的点正向压缩
{
used[u]=true;
for(int i=0;i<map1[u].size();i++)
if(!used[map1[u][i]])
dfs1(map1[u][i]);
order[cnt++]=u;
}

void dfs2(int u)
{
used[u]=true;
id[u]=color;
for(int i=0;i<map2[u].size();i++)
if(!used[map2[u][i]])
dfs2(map2[u][i]);
}

bool sat()
{
int i;
memset(used,0,sizeof(used));
color=cnt=0;
for(i=0;i<2*n;i++)
if(!used[i])
dfs1(i);
memset(used,0,sizeof(used));
for(i=cnt-1;i>=0;i--)
if(!used[order[i]])
{
color++;
dfs2(order[i]);
}
for(i=0;i<2*n;i+=2)
if(id[i]==id[i+1])
return 0;
return 1;
}


int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
break;
Init();
build_map1();
if(!sat())
printf("NO\n");
else
printf("YES\n");
}
return 0;
}

 

/*
这个是二维的:

*/

#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int Maxn=2010;//2*N
bool visit[Maxn];//标记
vector< vector<int> > adj;//正向图
vector< vector<int> > radj;//逆向图
int n,m,cnt,id[Maxn],order[Maxn];
//n表示点对数,m表示矛盾,id[]表示缩点后点对应的新点的标号
//order[]是强连通时使用korasaju记录搜索的次序
void Init()
{
for(int i=0; i<2*n; i++)
{
adj[i].resize(Maxn);
radj[i].resize(Maxn);
}
}
void init()
{
for(int i=0; i<2*n; i++)
{
adj[i].clear();
radj[i].clear();
}
}

void AddEdge(int from, int to)
{
adj[from].push_back(to);
radj[to].push_back(from);
}

void BuildGraph()
{
int u, v, x, y;
for(int i=0; i<m; i++)
{
scanf("%d%d%d%d", &x, &y, &u, &v);
u=2*x+u;
int uu=(u%2)?u-1:u+1;
v=2*y+v;
int vv=(v%2)?v-1:v+1;
AddEdge(u, vv);
AddEdge(v, uu);
}
}
void dfs(int u)//求强联通时的正向搜索进行标号
{
visit[u]=true;
int i,len=adj[u].size();
for(i=0; i<len; i++)
if(!visit[adj[u][i]])
dfs(adj[u][i]);
order[cnt++]=u;//标号从0开始,上面的点后标号,表示从正向的边存在
}

void rdfs(int u)//求强联通的逆向搜索
{
id[u]=cnt;//进行缩点标记
visit[u]=true;
int i,len=radj[u].size();
for(i=0; i<len; i++)
if(!visit[radj[u][i]])
rdfs(radj[u][i]);
}

void korasaju()
{
int i;
memset(visit,false,sizeof(visit));
for(cnt=0,i=0; i<2*n; i++) //正向搜一次
if(!visit[i])
dfs(i);
memset(id,0,sizeof(id));
memset(visit,false,sizeof(visit));
for(cnt=0,i=2*n-1; i>=0; i--) //从正向标记大的逆向搜一次.表示逆向的边也存在
{
if(!visit[order[i]])
{
cnt++;
rdfs(order[i]);//缩点后点的标号从1开始
}
}
}

bool solve()//判断同样的缩点中是否有矛盾的点
{
for(int i=0; i<2*n; i+=2)
if(id[i]==id[i+1])
return false;
return true;
}

int main()
{
adj.resize(Maxn);
radj.resize(Maxn);
Init();
while(scanf("%d%d", &n, &m)!=EOF)
{
init();
BuildGraph();
korasaju();
if(!solve()) puts("NO");
else puts("YES");
}
return 0;
}

 

posted on 2011-07-12 13:52  FreeAquar  阅读(303)  评论(0编辑  收藏  举报