• [Cerc2005]Knights of the Round Table


    题目描述

    有n个骑士经常举行圆桌会议,商讨大事。每次圆桌会议至少有3个骑士参加,且相互憎恨的骑士不能坐在圆桌的相邻位置。如果发生意见分歧,则需要举手表决,因此参加会议的骑士数目必须是大于1的奇数,以防止赞同和反对票一样多。知道那些骑士相互憎恨之后,你的任务是统计有多少骑士不可能参加任何一个会议。

    输入格式

    包含多组数据,每组数据格式如下: 第一行为两个整数n和m(1<=n<=1000, 1<=m<=10^6)。 以下m行每行包含两个整数k1和k2(1<=k1,k2<=n),表示骑士k1和k2相互憎恨。 输入结束标记为n=m=0

    输出格式

    对于每组数据,在一行中输出一个整数,即无法参加任何会议的骑士个数。


    我们显然需要让没有憎恨关系的骑士来参加会议。所以我们可以先建出原图的补图。

    然后我们发现,如果一些骑士要参加会议,那么这些骑士就要构成一个奇环。因为如果是偶环,那么环上的点就不能选完,也就是说必定会有有两个没有连边的点相邻着坐下。而邻座不能是憎恨的人,又由于我们建的是补图,没连边的点就是憎恨的骑士。所以偶环上的骑士不能参加会议。

    既然建的是补图,我们随便造个数据画一画可以隐约感觉到,不在同一个点双内的骑士不能参加同一次会议。

    其实原因也很简单,因为如果可以参加同一次会议,那么这两个点必须在同一个奇环内。而它们又不在同一个点双内,就不可能在同一个奇环内。

    然后这里有一条点双的定理:

    如果一个点双内部有奇环,那么整个点双的所有点也必定在某个奇环内。

    下面给出证明:我们在点双的奇环上取两个点u,v,那么必定存在奇环外的一个点w,使得u,v,w构成一个简单环。那么u->w的路径和v->w的路径上的点数就可能是奇或偶。不过无论奇或偶,都能跟原来的奇环构成另一个奇环,因为u通过奇环到达v有两条路径,这两条路径要么是奇数个点,要么是偶数个点,所以可以构成另一个奇环。


    所以我们的算法出来了:

    首先我们可以用Tarjan找出图中所有点双连通分量,然后枚举每个点双连通分量,我们判断它是不是一个奇环。判断奇环的方法就是:

    根据二分图的定义,一张二分图是不可以有奇环的。所以我们可以判断这个点双是否是二分图,如果不是那就有奇环。最后答案就是人数减去有奇环的点双的点数和。

    时间复杂度为O(N2+M),N2是因为要建补图。其它的时间复杂度都是O(N+M)。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #define maxn 1001
    #define maxm 1000001
    using namespace std;
      
    vector<int> to[maxn],dcc[maxn];
    bool g[maxn][maxn],able[maxn];//able表示能够参加会议
    int dfn[maxn],low[maxn],tot;
    int stack[maxn],top;
    int col[maxn],cnt;
    int vis[maxn];
    int n,m,ans;
      
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
      
    inline void init(){
        for(register int i=1;i<=n;i++) for(register int j=1;j<=n;j++) g[i][j]=false;
        for(register int i=1;i<=n;i++) dfn[i]=low[i]=vis[i]=col[i]=able[i]=0;
        for(register int i=1;i<=n;i++) to[i].clear(),dcc[i].clear();
        tot=cnt=0,ans=0;
    }
      
    void tarjan(int u){
        dfn[u]=low[u]=++tot;
        stack[++top]=u;
        for(register int i=0;i<to[u].size();i++){
            int v=to[u][i];
            if(!dfn[v]){
                tarjan(v),low[u]=min(low[u],low[v]);
                if(dfn[u]<=low[v]){
                    int w; cnt++;
                    do{ w=stack[top--],dcc[cnt].push_back(w); }while(w!=v);
                    dcc[cnt].push_back(u);
                }
            }else low[u]=min(low[u],dfn[v]);
        }
    }
      
    bool check(int u,int c,const int &id){
        vis[u]=c;
        for(register int i=0;i<to[u].size();i++){
            int v=to[u][i];
            if(col[v]!=id) continue;
            if(!vis[v]){
                if(check(v,3-c,id)) return true;
            }else if(vis[v]==c) return true;
        }
        return false;
    }
      
    int main(){
        while(scanf("%d %d",&n,&m)==2&&n&&m){
            init();
            for(register int i=1;i<=m;i++){
                int u=read(),v=read();
                g[u][v]=g[v][u]=true;
            }
            for(register int i=1;i<=n;i++){
                for(register int j=1;j<i;j++) if(!g[i][j]){
                    to[i].push_back(j),to[j].push_back(i);
                }
            }
      
            for(register int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
            for(register int i=1;i<=cnt;i++){
                for(register int j=0;j<dcc[i].size();j++){
                    col[dcc[i][j]]=i,vis[dcc[i][j]]=0;
                }
                if(check(dcc[i][0],1,i)){
                    for(register int j=0;j<dcc[i].size();j++) able[dcc[i][j]]=true;
                }
            }
            for(register int i=1;i<=n;i++) if(!able[i]) ans++;
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Jersey(1.19.1)
    Jersey(1.19.1)
    Jersey(1.19.1)
    Jersey(1.19.1)
    Jersey(1.19.1)
    Jersey(1.19.1)
    Jersey(1.19.1)
    Jersey(1.19.1)
    17. Letter Combinations of a Phone Number
    37.Sudoku Solver
  • 原文地址:https://www.cnblogs.com/akura/p/10958431.html
Copyright © 2020-2023  润新知