zoukankan      html  css  js  c++  java
  • poj2942(双联通分量,交叉染色判二分图)

    题意:一些骑士,他们有些人之间有矛盾,现在要求选出一些骑士围成一圈,圈要满足如下条件:1.人数大于1。2.总人数为奇数。3.有仇恨的骑士不能挨着坐。问有几个骑士不能和任何人形成任何的圆圈。

    思路:首先反向建立补图,然后问题转换成在图中找奇圈,圈肯定出现在双联通分量中,则求出图的双联通分量,又通过特性知道,一个双联通分量有奇圈则其中的点都可以出现在一个奇圈中。而对于奇圈的判定可以用交叉染色判断是非为二分图,二分图中肯定无奇圈,这里用tarjan算法得出割边(先将点入队),确定双联通分量的根节点,(对于队列中的点)然后进行染色判定,最后标记odd[]代表需要删除的点。

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define MAXN 1004
    #define MAXM 1001000
    
    int n,m,tot,count,top;
    int first[MAXN],DFN[MAXN],Low[MAXN],vis[MAXN],col[MAXN],mark[MAXN],stack[MAXM],odd[MAXN];
    int G[MAXN][MAXN];
    struct Edge
    {
        int st,to,next,vis;
    }edge[2*MAXM];
    void addedge(int a,int b)
    {
        edge[tot].to=b;
        edge[tot].st=a;
        edge[tot].next=first[a];
        edge[tot].vis=0;
        first[a]=tot++;
    }
    int find(int s)
    {
        for(int i=first[s];i!=-1;i=edge[i].next)
        {
            int t=edge[i].to;
            if(mark[t])
            {
                if(col[t]==-1)
                {
                    col[t]=!col[s];
                    return find(t);
                }
                else if(col[t]==col[s]) return 1;
            }
        }
        return 0;
    }
    void color(int s)
    {
        int i;
        memset(mark,0,sizeof(mark));
        do{
            i=stack[top--];
            mark[edge[i].st]=1;
            mark[edge[i].to]=1;
        }while(edge[i].st!=s);
        memset(col,-1,sizeof(col));
        col[s]=0;
        if(find(s))
        {
            for(int i=1;i<=n;i++)
            {
                if(mark[i])
                    odd[i]=1;
            }
        }
    }
    void dfs(int s)
    {
        DFN[s]=Low[s]=++count;
        for(int i=first[s];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(edge[i].vis)continue;
            edge[i].vis=edge[i^1].vis=1;
            stack[++top]=i;
            if(!DFN[v])
            {
                dfs(v);
                Low[s]=min(Low[s],Low[v]);
                if(Low[v]>=DFN[s])color(s);
            }
            else
            {
                Low[s]=min(Low[s],DFN[v]);
            }
        }
    }
    int main()
    {
        while(scanf("%d%d",&n,&m),n||m)
        {
            memset(G,0,sizeof(G));
            for(int i=1;i<=m;i++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                G[a][b]=1;
                G[b][a]=1;
            }
            tot=0;
            memset(first,-1,sizeof(first));
            for(int i=1;i<=n;i++)
            {
                for(int j=i+1;j<=n;j++)
                {
                    if(G[i][j]==0)
                    {
                        addedge(i,j);
                        addedge(j,i);
                    }
                }
            }
            memset(DFN,0,sizeof(DFN));
            memset(odd,0,sizeof(odd));
            count=0;top=0;
            for(int i=1;i<=n;i++)
            {
                if(!DFN[i])
                    dfs(i);
            }
            int ans=0;
            for(int i=1;i<=n;i++)
            {
                if(!odd[i])
                    ans++;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    


     

  • 相关阅读:
    Axure 实现数字自动加键功能(点击“+”数字加1,点击“-”数字减1)
    Axure 实现批量的勾选和反选
    传说中的AutoCAD公司
    Autodesk 最新开发技术研讨会-北京-上海-武汉-成都-西安-PPT下载
    发布App,赢iPad mini + 美金100$
    无插件的大模型浏览器Autodesk Viewer开发培训-武汉-2014年8月28日 9:00 – 12:00
    为Autodesk Viewer添加自定义工具条的更好方法
    为Autodesk Viewer添加自定义工具条
    Autodesk 最新开发技术研讨会 -8月22日-Autodesk北京办公室
    请保护我们的地球
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134123.html
Copyright © 2011-2022 走看看