• Knights of the Round Table(缩点+判奇环) poj 2942 && 洛谷SP2878


    题目

    分析:

    原题给的是不能相连的点,直接打标记转换为补图,对所有能坐在一起的点连边。

    然后就转换成了一张有许多个环的图,题中要求不在奇环中的点,那么就对每一个v-dcc  dfs一次,看是否包含奇环。

    如果说一个dcc包含了一个奇环,那么在dcc中的每一个点,都至少在一个奇环上。

    证明:

    dcc上的每一个点至少在一个环上,而这个环一定包含两个在奇环上的点(否则就可以删掉一个点使得其不连通),在奇环上的两个点可以与某一点组成一个奇环。

    判奇环:

    给每一个点一个颜色,如果两个点之间有连边且颜色一样说明遍历到了一个奇环。

    点的颜色最好选择1和2,注意赋初值。

    void dfs(int u,int col,int now)
    {
        c[u]=col;
        for(ri i=head[u];i;i=nex[i]){
            int v=to[i];
            if(bel[v]!=now) continue;
            if(c[v] && c[v]==c[u]) { fl=1; return ; }
            if(!c[v]) dfs(v,3-col,now);//1 2 col
        }
    }
    判奇环

    tarjan求点双、割点模板:

    for(ri i=1;i<=n;++i) if(!dfn[i]) tarjan(i,i);
    
    
    void tarjan(int u,int rt)
    {
        dfn[u]=low[u]=++Ti; stk[++top]=u;
        if(u==rt && head[u]==0){
            dcc[++cnt].push_back(u);
            return ;
        }
        for(ri i=head[u];i;i=nex[i]){
            int v=to[i];
            if(!dfn[v]){
                tarjan(v,rt);
                low[u]=min(low[u],low[v]);
                if(dfn[u]<=low[v]){
                    if(fl>1 || u!=rt) cut[u]=true;//判断割点 
                    cnt++; int tmp;
                    do{
                        tmp=stk[top];
                        top--;
                        dcc[cnt].push_back(tmp);
                    }while(tmp!=v);
                    dcc[cnt].push_back(u);//u记得把它本身也加入点双之间 
                }
            }
            else low[u]=min(low[u],dfn[v]);
        }
    }
    tarjan

    完整代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define N 1005
    #define M 1000005
    #define ri register int
    int stk[N],top=0,bel[N],low[N],dfn[N],n,m,hate[N][N],can[N];
    int tot=0,head[N],nex[M],to[M],Ti=0,cnt=0,c[N],cut[N];
    vector<int> dcc[N];
    void add(int a,int b) { to[++tot]=b; nex[tot]=head[a]; head[a]=tot; }
    void init()
    {
        tot=0,Ti=0,cnt=0;
        memset(hate,0,sizeof(hate));
        for(ri i=1;i<=n;++i) can[i]=low[i]=dfn[i]=stk[i]=head[i]=c[i]=bel[i]=0,dcc[i].clear();
    }
    void tarjan(int u,int rt)
    {
        dfn[u]=low[u]=++Ti; stk[++top]=u;
        if(u==rt && head[u]==0){
            dcc[++cnt].push_back(u);
            return ;
        }
        for(ri i=head[u];i;i=nex[i]){
            int v=to[i];
            if(!dfn[v]){
                tarjan(v,rt);
                low[u]=min(low[u],low[v]);
                if(dfn[u]<=low[v]){
                    if(fl>1 || u!=rt) cut[u]=true;//判断割点 
                    cnt++; int tmp;
                    do{
                        tmp=stk[top];
                        top--;
                        dcc[cnt].push_back(tmp);
                    }while(tmp!=v);
                    dcc[cnt].push_back(u);//u记得把它本身也加入点双之间 
                }
            }
            else low[u]=min(low[u],dfn[v]);
        }
    }
    int fl;
    void dfs(int u,int col,int now)
    {
        c[u]=col;
        for(ri i=head[u];i;i=nex[i]){
            int v=to[i];
            if(bel[v]!=now) continue;
            if(c[v] && c[v]==c[u]) { fl=1; return ; }
            if(!c[v]) dfs(v,3-col,now);//1 2 col
        }
    }
    int main()
    {
        int a,b;
        while(1){
            scanf("%d%d",&n,&m);
            if(n==0 && m==0) break;
            init();
            for(ri i=1;i<=m;++i) scanf("%d%d",&a,&b),hate[a][b]=1,hate[b][a]=1;
            for(ri i=1;i<=n;++i)
             for(ri j=i+1;j<=n;++j)
              if(!hate[i][j])
               add(i,j),add(j,i);
            for(ri i=1;i<=n;++i) if(!dfn[i]) tarjan(i,i);
            /*for(ri i=1;i<=cnt;++i){输出点双 
                printf("i:%d
    ",i);
                for(ri j=0;j<dcc[i].size();++j) printf("%d ",dcc[i][j]);
            }*/
            for(ri i=1;i<=cnt;++i){
                fl=0;
                for(ri j=0;j<dcc[i].size();++j)
                bel[dcc[i][j]]=i,c[dcc[i][j]]=0;
                dfs(dcc[i][0],1,i);
                if(fl){
                    for(ri j=0;j<dcc[i].size();++j)
                    can[dcc[i][j]]=true;
                }
            }
            int ans=0;
            for(ri i=1;i<=n;++i) if(!can[i]) ans++;
            printf("%d
    ",ans);/**/
        }
        return 0;
    }
    /*
    5 5
    1 4
    1 5
    2 5
    3 4
    4 5
    0 0
    */
    View Code
  • 相关阅读:
    在smarty模板中截取指定长度的字符串
    HTMl中Meta标签详解以及meta property=og标签含义
    seo标题关键字描述字数限制Title,keywords,description长度最长多长 ?
    网站title,meta,description如何设置,长度大小多少合适!
    php如何开启gd2扩展
    PHP生成带logo图像二维码的两种方法
    [uart]1.Linux中tty框架与uart框架之间的调用关系剖析
    TCP/IP四层模型和OSI七层模型的概念
    [platform]新旧内核的device设备注册对比
    [platform]linux platform device/driver(三)--Platform Device和Platform_driver注册过程之代码对比
  • 原文地址:https://www.cnblogs.com/mowanying/p/11640933.html
Copyright © 2020-2023  润新知