SP2878 KNIGHTS - Knights of the Round Table 题解

对于原图上的仇恨关系,我们可以重新建边,新的边表示两个人可以相邻。一次会议当中所有合法的点一定来源于一个点双联通分量,因为如果有两个点不在同一个双联通分量的话,因为两个点双联通分量之间最多只有一条边连接,那么这样的会议一定会面临两个点中有一个点不能和会议当中其他的点相邻。

接下来我们思考如何在同一个双联通分量内部计算出合法的点对数量,首先奇环上面的点一定是符合定义的,如果不在奇环上面的点呢?对于一个点双联通分量内部的点而言,因为一个奇环可以拆分成一条奇数长度的链和一条偶数长度的链,所以说经过所有点联通分量内部点的那条环路一定可以通过选择走奇链还是偶链形成一个新的奇环。所以说只要一个点双联通分量内部是存在奇环的,那么所有的点都一定存在一个奇环上面,找奇环可以用染色法。我们只需要记录出每一个双联通分量,然后找奇环就可以。

代码

#include <bits/stdc++.h>
using namespace std;

const int N=1e3+5;

int mp[N][N];
int n,m;

int dfn[N],low[N],idx;
vector<vector<int>> bcc;
stack<int> stk;
bool flag[N],vis[N],is[N];
int number[N];

void Tarjan(int u,int fa){
    dfn[u]=low[u]=++idx;
    stk.push(u);
    for(int v=1;v<=n;v++){
        if(!mp[u][v]||v==fa) continue; 
        if(!dfn[v]){
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]){
                int x;
                vector<int> res;
                res.push_back(u);
                do{
                    x=stk.top();stk.pop();
                    res.push_back(x);
                }while(x^v);
                bcc.push_back(res);
            }
        }else low[u]=min(low[u],dfn[v]);
    }
}

void sol(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            mp[i][j]=0;
        }
        flag[i]=vis[i]=is[i]=false;
        dfn[i]=low[i]=number[i]=0;
    }
    idx=0;
    if(bcc.size()) bcc.clear();
    for(int i=0;i<m;i++){
        int u,v;
        cin>>u>>v;
        mp[u][v]=mp[v][u]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j) mp[i][j]=0;
            else mp[i][j]^=1;
        }
    }

    for(int i=1;i<=n;i++){
        if(!dfn[i]) Tarjan(i,i);
    }


    auto dfs=[&](auto &&self,int u,int x,int cnt)->bool{
        vis[u]=1;
        number[u]=x;
        for(int v:bcc[cnt]){
            if(mp[u][v]==0) continue;
            if(vis[v]){
                if(number[v]==x) return false;    
            }else if(!self(self,v,x^1,cnt)) return false;
        }
        return true;
    };

    // for(int i=0;i<bcc.size();i++){
    //     cout<<i<<'\n';
    //     for(int j=0;j<bcc[i].size();j++){
    //         cout<<bcc[i][j]<<" ";
    //     }
    //     cout<<'\n';
    // }

    int ans=0;
    for(int i=0;i<bcc.size();i++){
        bool f=dfs(dfs,bcc[i][0],0,i);
        for(int j=0;j<bcc[i].size();j++){
            if(!f)   is[bcc[i][j]]=true;
            vis[bcc[i][j]]=false;
        }
        
    }
    for(int i=1;i<=n;i++) if(!is[i]) ans++; 
    cout<<ans<<'\n';
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);

    while(1){
        cin>>n>>m;
        if((n|m)==0) return 0;
        sol();
    }
}
posted @ 2026-03-14 14:02  1445141  阅读(13)  评论(0)    收藏  举报