• 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;
    }
    


     

  • 相关阅读:
    动态绑定表格
    双缓冲设置控件
    编写模块化插件式应用程序
    网上收集整理SharePoint的母版页master占位符(改动不大)
    改变SharePoint工作流任务的界面
    SharePoint定时器作业部署步骤
    定时器作业将sap数据更新至列表库
    网络没问题,MSN登录不了解决方法
    以后就搬家到cnblogs吧。
    记录我的第一个OpenGL程序
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134123.html
Copyright © 2020-2023  润新知