• 2-SAT(HDU-3062 party)


    2-SAT(HDU-3062 party)

    解决问题类型:

    书本定义:给一个布尔方程,判断是否存在一组解使整个方程为真,被称为布尔方程可满足性问题(SAT)

    因为本题只有0,1(丈夫 妻子只能去一个人),所以是2-SAT。

    算法思想:

    根据题意:对于(a ,a' )(b ,b' ),如果a ,b 构成仇恨问题,那么a 若出席,b' 一定出席,b若出席,a ‘ 一定出席;据此他们之间可以建有向边(有向边的意义一定要明白! ! !代码中建边时已经标注)。而强连通分量的特点就是可以缩点,判断两点之间是否可以相互到到达(对此图tarjan缩点,若一对夫妻在一个强连通分量中,表示这对夫妻之间有一条逻辑上的有向边)

    可能脑子太迟钝了,好不容易悟出来,不过还是很开心

    可能因为学了数据结构,觉得邻接表就是单链表的头插法,有木有!!!

    撸代码:

    #include<stdio.h>
    #include<string.h>
    #include<stack>
    using namespace std;
    struct node
    {

        int v,nex;
    } edge[1000007];
    int dfn[2007],low[2007],instack[2007],head[2007],index;
    int cir,belong[2007],cnt;
    stack<int>s;
    void init()
    {
        for(int i=0; i<=2005; i++)
        {
            head[i]=-1;
            dfn[i]=0;
            low[i]=0;
            instack[i]=0;
            belong[i]=0;
        }
        while(!s.empty())
            s.pop();
        cir=0;
        index=0;
        cnt=0;
    }
    void add_edge(int u,int v)
    {
        edge[cnt].v=v;
        edge[cnt].nex=head[u];
        head[u]=cnt++;
    }/*邻接表相当于链表的头插法*/
    void Tarjan(int u)
    {
        instack[u]=1;
        s.push(u);
        dfn[u]=low[u]=++index;
        for(int i=head[u]; i!=-1; i=edge[i].nex)
        {
            int v=edge[i].v;
            if(!dfn[v])
            {
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(instack[v])
            {
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u])
        {
            ++cir;
            int node;
            do
            {
                node=s.top();
                s.pop();
                instack[node]=0;
                belong[node]=cir;
            }
            while(node!=u);
        }
        return ;
    }
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            init();
            int a,b,c,d;
            for(int i=1; i<=m; i++)
            {
                scanf("%d%d%d%d",&a,&b,&c,&d);
                a=(a<<1)+c;
                b=(b<<1)+d;/*a b 不能在一块*/
                add_edge(a,b^1);
                add_edge(b,a^1);
                /*!!! 为什么没有a^1和b^1:有向边意义:若选a必选b^1,b同理*/
            }
            for(int i=0; i<n*2; i++)
                if(!dfn[i])
                    Tarjan(i);
            int flag=0;
            for(int i=0; i<n; i++)
            {
                if(belong[i<<1]==belong[(i<<1)^1])/*!!!若某0 1点在一个连通分量,说明两个都要选,自相矛盾*/
                    flag=1;
            }
            if(flag)
                printf("NO ");
            else
                printf("YES ");
        }
        return 0;
    }

    DREAM_yao:若有错误,热烈欢迎指正

  • 相关阅读:
    liunx各命令及全称
    window启动数据库服务命令
    拉取github指定分支上的代码
    python项目学习
    客户展示 增删改查
    登录 注册功能 表梳理
    java简历
    go语言数组
    go语言 变量作用域
    go语言函数
  • 原文地址:https://www.cnblogs.com/HappyKnockOnCode/p/12623252.html
Copyright © 2020-2023  润新知