0
点赞
收藏
分享

微信扫一扫

POJ3905 Perfect Election【2-SAT】【Tarjan】


题目链接:

​​http://poj.org/problem?id=3905​​


题目大意:

有N个候选人,有M组要求,每组要求关系到候选中的两个人A和B,"+A +B"表示A和B中至少

有一人被选中,"-A -B"表示A和B中至少有一人不被选中。"+A -B"表示A被选中和B不被选中两

件事至少发生一件。"-A +B"表示A不被选中和B被选中至少发生一件。那么问题来了:是否存在

M组要求全部符合的方案。


思路:在本题中,每个人都有两种状态,一种是选中,一种是不选中。可以把一个人i拆成两个点

Pi和P(i+N),分别表示当选和落选。那么两个人i和j的关系就可以表示为以下四种:

i和j至少有一个人当选:i->j+N,j->i+N

i和j至少有一个人落选:i+N->j,j+N->i

i当选,j落选:              i->j,j+N->i+N

i落选,j当选:              i+N->j+N,j->i

那么根据上面的关系建有向图,那么问题就变为从图中选出N个点,并且Ai和A(i+N)的点不能同时

被选择,使其满足2-SAT条件。求出图的强连通分量,如果选中强连通分量中的一个点,那么就必

须选中强连通分量中的所有点,如果Ai和!Ai都在一个强连通分量里,则产生矛盾,那么2-SAT无解。

如果都不在一个强连通分量里,则2-SAT有解。最后的步骤就是用Tarjan了求强连通分量并缩点,之

后判断是否存在Ai和A(i+N)在一个强连通分量里。如果存在,则方案不满足,如果不存在,则方案

满足。


AC代码:


<span style="font-family:Microsoft YaHei;font-size:18px;">#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int MAXN = 2200;
const int MAXM = MAXN*MAXN;

struct EdgeNode
{
int to;
int next;
}Edges[MAXM];

int Head[MAXN];
int dfn[MAXN],low[MAXN],belong[MAXN],Stack[MAXN],vis[MAXN];
int m,id,lay,scc,N,M;

void AddEdges(int u,int v)
{
Edges[id].to = v;
Edges[id].next = Head[u];
Head[u] = id++;
}

void TarBFS(int pos)
{
dfn[pos] = low[pos] = ++lay;
Stack[m++] = pos;
vis[pos] = 1;

for(int i = Head[pos]; i != -1; i = Edges[i].next)
{
int v = Edges[i].to;
if( !dfn[v] )
{
TarBFS(v);
low[pos] = min(low[pos],low[v]);
}
else if(vis[v])
low[pos] = min(low[pos],low[v]);
}
int v;
if(dfn[pos] == low[pos])
{
++scc;
do
{
v = Stack[--m];
belong[v] = scc;
vis[v] = 0;
}while(v != pos);
}
}

int main()
{
int u,v;
while(~scanf("%d%d",&N,&M))
{
id = m = scc = lay = 0;
memset(Head,-1,sizeof(Head));
memset(vis,0,sizeof(vis));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(belong,0,sizeof(belong));
for(int i = 0; i < M; ++i)
{
scanf("%d%d",&u,&v);
int a = abs(u);
int b = abs(v);

if(u > 0 && v > 0)
{
AddEdges(a+N,b);
AddEdges(b+N,a);
}

if(u < 0 && v < 0)
{
AddEdges(a,b+N);
AddEdges(b,a+N);
}

if(u > 0 && v < 0)
{
AddEdges(a+N,b+N);
AddEdges(b,a);
}

if(u < 0 && v > 0)
{
AddEdges(a,b);
AddEdges(b+N,a+N);
}
}

for(int i = 1; i <= 2*N; ++i)
if( !dfn[i] )
TarBFS(i);
int ans = 1;
for(int i = 1; i <= N; ++i)
{
if(belong[i] == belong[i+N])
{
ans = 0;
break;
}
}

printf("%d\n",ans);
}

return 0;
}
</span>





举报

相关推荐

0 条评论