首页 > 技术文章 > bzoj2184: 任意图的匹配

ccz181078 2017-01-19 18:13 原文

Description

每天都要考,每天都要讲,大家注意力都集中不起来了,每天听解题报告时都有人交头接耳(也包括我,呵呵)。这样做大大的影响的学习效率(可能吧)。于是,有些好奇心重的同学就开始研究,怎样才会最吵。培训的总共有N个人,但不是每两人之间都讲话,只有一些人有话题聊,而且一个人可能会和多个人有话题(共M对人)。如果所有同学都说在话,教室里最吵。你的任务就是求出把说话者对数控制在多少人以内,无论如何教室里不会变得最吵?注意:A和B说话,同时B和C说话,这算两对人说话。

Input

第一行两个整数N,M。接下来M行,每行两个整数x,y表示x和y有话题聊。

Output

一行,一个整数表示要把说话者对数控制在多少以内,无论如何教室里不最吵。

若有孤立点,则答案为M,否则设最少用k条边覆盖所有点,则答案为k-1

k=N-最大匹配

#include<bits/stdc++.h>
const int N=10007;
int es[N],enx[N],e0[N],ep,q[N],ql,qr,n,m,f[N],nx[N],pv[N],t[N],ts[N],tk=0,ans=0;
void ae(int a,int b){
    es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
    es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
}
int get(int x){return x!=f[x]?f[x]=get(f[x]):x;}
int lca(int x,int y){
    ++tk;
    while(1){
        if(x){
            x=get(x);
            if(ts[x]==tk)return x;
            ts[x]=tk;
            x=pv[nx[x]];
        }
        std::swap(x,y);
    }
}
void mg(int a,int b){
    while(a!=b){
        int w=nx[a],u=pv[w];
        if(get(u)!=b)pv[u]=w;
        if(t[a]==2)t[q[++qr]=a]=1;
        if(t[w]==2)t[q[++qr]=w]=1;
        if(a==f[a])f[a]=b;
        if(w==f[w])f[w]=b;
        a=u;
    }
}
int bfs(int w0){
    for(int i=1;i<=n;++i)f[i]=i,pv[i]=0,t[i]=0;
    ql=qr=0;
    q[++qr]=w0;
    while(ql!=qr){
        int w=q[++ql];
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u==nx[w]||get(w)==get(u)||t[u]==2)continue;
            if(t[u]==1){
                int v=lca(w,u);
                if(get(w)!=v)pv[w]=u;
                if(get(u)!=v)pv[u]=w;
                mg(w,v);mg(u,v);
            }else if(nx[u]){
                pv[u]=w;
                t[u]=2;
                t[q[++qr]=nx[u]]=1;
            }else{
                while(w){
                    int a=nx[w];
                    nx[w]=u;nx[u]=w;
                    u=a;
                    w=pv[u];
                }
                return 1;
            }
        }
    }
    return 0;
}
int main(){
    while(scanf("%d%d",&n,&m)==2){
        memset(e0,0,sizeof(int)*(n+1));
        memset(nx,0,sizeof(int)*(n+1));
        ep=2;
        for(int i=1,a,b;i<=m;++i){
            scanf("%d%d",&a,&b);
            ae(a,b);
        }
        for(int i=1;i<=n;++i)if(!e0[i]){
            printf("%d\n",m);
            goto o;
        }
        ans=0;
        for(int i=1;i<=n;++i)if(!nx[i])ans+=bfs(i);
        printf("%d\n",n-ans-1);
        o:;
    }
    return 0;
}

 

推荐阅读