zoukankan      html  css  js  c++  java
  • poj 2942 Knights of the Round Table 夜

    http://poj.org/problem?id=2942

    弄了一天 终于搞定

    伦理知识我建议看这里 http://blog.csdn.net/lyy289065406/article/details/6756821

    讲的很详细 不过代码的风格不是很好接受

    刚开始我以为是所有的骑士全围着一张桌子坐

    后来才知道某个骑士只要能和任意其他符合要求的骑士组成一个会议小组他就可以留下

    开会条件:

    a 骑士的数量必须是奇数而且不能是1

    b 他的两个邻居不是他仇恨的

    给出原图后建补图

    求点的双联通

    对补图每求一个割点就对其进行操作

    出栈操作 但是联通根点不出栈 (因为它可能属于其他的联通图)

    对其联通图进行遍历 对所有的奇环内的点进行标记 他们是可留下的

    整个图有可能不联通 也就是说图会有好几块 要注意

    代码及其注释:

    #include<iostream>
    #include<cstring>
    #include<stack>
    #include<cstdio>
    #include<queue>
    
    using namespace std;
    
    const int N=1005;
    struct node
    {
        struct tt *next;
    }mem[N];
    struct tt
    {
        struct tt *next;
        int j;
    };
    bool visited[N];
    stack<int>str;
    bool in[N];
    int low[N];
    int deep;
    int dfn[N];
    bool uppoint[N];
    bool link[N][N];
    int color[N];
    bool save[N];
    void build(int i,int j)
    {
        struct tt *t=new tt;
        t->j=j;
        t->next=mem[i].next;
        mem[i].next=t;
    }
    void Clear(int n)//每次对邻接表进行清理
    {
       struct tt *t;
       for(int i=1;i<=n;++i)
       {
           while(mem[i].next!=NULL)
           {
               t=mem[i].next;
               mem[i].next=t->next;
               delete t;
           }
       }
    }
    bool dfs(int x,int c)//交叉染色看是否有奇环
    {
        color[x]=c;
        struct tt *t=mem[x].next;
        while(t!=NULL)
        {
            if(uppoint[t->j])
            {
                if(color[t->j]==0)
                {
                    if(dfs(t->j,-c))
                    return true;
                }else if(color[t->j]==color[x])
                {
                    return true;
                }
            }
            t=t->next;
        }
        return false;
    }
    bool Savepoint(int pre,int x)//有奇环的话对其所有的环进行 标记(留下) 但一些非环分支不标记
    {
        color[x]=1;
        struct tt *t=mem[x].next;
        bool ok=false;
        while(t!=NULL)
        {
            if(uppoint[t->j])
            {
                if(color[t->j]==1)
                {
                    if(t->j!=pre)
                    ok=true;
                }
                else
                {
                    if(Savepoint(x,t->j))
                    ok=true;
                }
            }
            t=t->next;
        }
        if(ok)
        save[x]=true;
        return ok;
    }
    void find(int x)//找可留下的骑士
    {
        memset(uppoint,false,sizeof(uppoint));//标记是否属于此联通图
        uppoint[x]=true;
        while(str.top()!=x)
        {
            in[str.top()]=false;
            uppoint[str.top()]=true;
            str.pop();
        }
        memset(color,0,sizeof(color));//染色数组
        if(dfs(x,1))//有奇环
        {
          memset(color,0,sizeof(color));
          Savepoint(x,x);//对此连通图内所有可构成环的点进行标记
        }
    }
    void Tanjan(int pre,int x)
    {
        ++deep;
        dfn[x]=low[x]=deep;
        visited[x]=true;
        in[x]=true;
        str.push(x);
        struct tt *t=mem[x].next;
        while(t!=NULL)
        {
            if(visited[t->j]==false)
            {
                Tanjan(x,t->j);
                low[x]=min(low[x],low[t->j]);
                if(low[x]==dfn[x])//每出现割点就找可留下的骑士
                {
                   find(x);
                }
            } else
            if(in[t->j]&&pre!=t->j)
            {
                low[x]=min(low[x],dfn[t->j]);
            }
            t=t->next;
        }
    }
    int main()
    {
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            if(n==0&&m==0)
            break;
            memset(link,false,sizeof(link));
            while(m--)
            {
                int i,j;
                scanf("%d%d",&i,&j);
                link[i][j]=link[j][i]=true;//保存原图
            }
            for(int i=1;i<=n;++i)
            {
                for(int j=1;j<=n;++j)
                {
                    if(i!=j&&link[i][j]==false)
                    {
                        build(i,j);//建补图
                    }
                }
            }
            memset(visited,false,sizeof(visited));
            memset(in,false,sizeof(in));
            memset(save,false,sizeof(save));
            deep=0;
            for(int i=1;i<=n;++i)
            {
                if(visited[i]==false)//防止补图不联通
                {
                     while(!str.empty())
                     str.pop();
                     Tanjan(i,i);
                }
            }
            int sum=0;
            for(int i=1;i<=n;++i)
            {
                if(!save[i])
                ++sum;
            }
            printf("%d\n",sum);
            Clear(n);
        }
        return 0;
    }
    
    
  • 相关阅读:
    安卓手机!用swiper做轮播效果,两张图片之间会有一个像素的空白
    手机端swiper快速滑动会有白屏
    axios请求下载excel文件
    人人都能学会的webpack5搭建vue3项目(二)配置Vue
    人人都能学会的webpack5搭建vue3.0项目,可应用于生产环境 (一)
    mybatis 生成 mapper文件
    超强工具类系列
    mybatis 自动生成mapper文件
    面试
    linux安装mysql8.0.25
  • 原文地址:https://www.cnblogs.com/liulangye/p/2528988.html
Copyright © 2011-2022 走看看