UVA1364 Knights of the Round Table

链接

https://vjudge.net/problem/UVA-1364

题解

先建图,如果两个人可以相邻就连无向边
那么一次会议就是一个环,且环的大小是不小于 3 3 3的奇数
那这个题就相当于询问有多少个点不在任何一个满足条件的环中
首先一个环上的点肯定属于同一个双联通分量
现在对于每个点,我想看看有没有一个满足条件的环包含这个点
那么就考察一下所有包含这个点的双连通分量
首先我知道“一个图是二分图当且仅当这个图中所有的环的点数都是偶数”
原命题的逆否命题是:“一个图中含有奇数环当且仅当它不是二分图”
那么对于一个双联通分量,如果它不是二分图(这一点我可以通过黑白染色来判定),就有一个奇数环
取奇数环上的两个点 ( u 1 , u 2 ) (u_1,u_2) (u1,u2)
在这里插入图片描述
对于双联通分量里的一个点 v v v,如果它在这个奇环上,那么这个奇环就对应了一种合法方案
如果不在奇环上,那么根据双联通的性质,我可以找到两条只在 v v v处相交的路径 v → u 1 v\rightarrow u_1 vu1 v → u 2 v \rightarrow u_2 vu2
在这里插入图片描述
蓝色和红色路径肯定一奇一偶,所以不管路径 u 1 − v − u 2 u_1 - v - u_2 u1vu2上的点数是奇数还是偶数,我总能找到包含 v v v的环使上面有奇数个点
综上所述,只要这个双联通分量不是二分图,那么这个双连通分量里所有的点就都可以在一个奇环上

代码

#include <bits/stdc++.h>
#define maxn 1010
#define maxe 1000010
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
struct Graph
{
    int etot, head[maxn], to[maxe], next[maxe], w[maxe];
    void clear(int N)
    {
        for(int i=1;i<=N;i++)head[i]=0;
        etot=0;
    }
    void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
}G;
struct BiconnectedComponent
{
    int dfn[maxn], low[maxn], iscut[maxn], bccno[maxn], tim, tot;
    vector<int> bcc[maxn];
    typedef pair<int,int> pii;
    stack<pii> s;
    void dfs(Graph &G, int pos, int pre)
    {
        int ch=0;
        dfn[pos]=low[pos]=++tim;
        for(auto p=G.head[pos];p;p=G.next[p])
            if(!dfn[G.to[p]])
            {
                ch++;
                s.push(pii(pos,G.to[p]));
                dfs(G,G.to[p],pos);
                low[pos]=min(low[pos],low[G.to[p]]);
                if(low[G.to[p]]>=dfn[pos])
                {
                    iscut[pos]=1;
                    bcc[++tot].clear();
                    while(1)
                    {
                        auto u=s.top().first, v=s.top().second; s.pop();
                        if(bccno[u]!=tot)bcc[tot].push_back(u), bccno[u]=tot;
                        if(bccno[v]!=tot)bcc[tot].push_back(v), bccno[v]=tot;
                        if(u==pos and v==G.to[p])break;
                    }
                }
            }
            else if(dfn[G.to[p]]<dfn[pos] and G.to[p]!=pre)
            {
                s.push(pii(pos,G.to[p]));
                low[pos]=min(low[pos],dfn[G.to[p]]);
            }
            if(pre<0 and ch==1)iscut[pos]=0;
    }
    void run(Graph &G, int N)
    {
        int i;
        for(i=1;i<=N;i++)bccno[i]=iscut[i]=dfn[i]=0;
        tim=tot=0;
        for(i=1;i<=N;i++)if(!dfn[i])dfs(G,i,-1);
    }
}BCC;
int col[maxn], flag, in[maxn];
void dfs(int pos)
{
    for(auto p=G.head[pos];p;p=G.next[p])
        if(in[G.to[p]])
            if(!col[G.to[p]])
            {
                col[G.to[p]]=col[pos]^3;
                dfs(G.to[p]);
            }
            else if(col[G.to[p]]==col[pos])flag=false;
}
int m[maxn][maxn], N, M, ok[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int i, j, u, v;
    while(cin>>N>>M, N)
    {
        G.clear(N);
        for(i=1;i<=N;i++)ok[i]=0;
        for(i=1;i<=N;i++)for(j=1;j<=N;j++)m[i][j]=1;
        for(i=1;i<=M;i++)
        {
            cin>>u>>v;
            m[u][v]=m[v][u]=0;
        }
        for(i=1;i<=N;i++)for(j=1;j<=N;j++)
            if(i!=j and m[i][j])G.adde(i,j);
        BCC.run(G,N);
        for(i=1;i<=BCC.tot;i++)
        {
            for(auto x:BCC.bcc[i])in[x]=true, col[x]=0;
            flag=true;
            dfs(BCC.bcc[i].at(0));
            if(!flag)for(auto x:BCC.bcc[i])ok[x]=true;
            for(auto x:BCC.bcc[i])in[x]=false;
        }
        int ans=0;
        for(i=1;i<=N;i++)ans+=!ok[i];
        cout<<ans<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值