POJ3648 2-sat强连通缩点法

题意:有一对新人结婚,邀请n对夫妇去参加婚礼。有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:1.每对夫妇不能坐在同一侧 2.n对夫妇之中可能有通奸关系(包括男男,男女,女女),有通奸关系的不能同时坐在新娘的对面,可以分开坐,可以同时坐在新娘这一侧。如果存在一种可行的方案,输出与新娘同侧的人。

解析:分析可知用2-sat选择与新郎同侧的人,那么与新娘同侧的人就对应知道了,这样求解答案会简单很多。在建图过程中要注意,新娘和新郎中必须选择新郎,因此要从新娘到新郎连一条边,剩下就是经典的tarjan缩点+拓扑排序求答案了。

代码如下:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1005*2;
int low[maxn],dfn[maxn],st[maxn],num[maxn],belong[maxn],in[maxn],cf[maxn];
int top,index,scc;
int color[maxn];
bool instack[maxn];
vector g[maxn];
vector > dag;
void tarjan(int now)
{
    low[now]=dfn[now]=++index;
    st[top++]=now;
    instack[now]=true;
    for(int i=0;ilow[to])
                low[now]=low[to];
        }
        else if(instack[to]&&low[now]>dfn[to])
            low[now]=dfn[to];
    }
    if(low[now]==dfn[now])
    {
        scc++;
        int to;
        do
        {
            to=st[--top];
            instack[to]=false;
            belong[to]=scc;
            num[scc]++;
        }while(now!=to);
    }
}
bool solvable(int n)
{
    memset(dfn,0,sizeof dfn);
    memset(instack,0,sizeof instack);
    memset(num,0,sizeof num);
    index=scc=top=0;
    for(int i=0;i());
    memset(in,0,sizeof in);
    memset(color,0,sizeof color);
    for(int now=0;now q;
    for(int i=1;i<=scc;i++)
    {
        if(in[i]==0)
            q.push(i);
    }
    while(!q.empty())
    {
        int now=q.front();q.pop();
        if(color[now]==0)
        {
            color[now]=1;
            color[cf[now]]=-1;
        }
        int siz=dag[now].size();
        for(int i=0;i

 

另:发现用HDU1814的染色法同样可以解决此问题,而且代码实现难度要小得多,复杂度却几乎相同,难道强连通分量缩点法有什么特别的用处吗?求各路大牛指点....

代码如下:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1005*2;
vector g[maxn];
bool v[maxn];
int st[maxn],top;
bool dfs(int u)
{
    if(v[u^1]) return false;
    if(v[u]) return true;
    v[u]=true;
    st[top++]=u;
    for(int i=0;i

 

你可能感兴趣的:(acm)