[bzoj][ONTAK2010]Life of the Party——二分图最大匹配关键点 大佬们的博客 Some Links

题目大意:

求一个二分图的最大匹配关键点(即不论如何都在最大匹配中的点)。

思路:

最大匹配一般用匈牙利算法来求,即不断重复而找到一条交替链,一条交替链必须要满足两头都是未匹配点才可以成为增广路。
换句话来说,在最大匹配的图中,不可能存在两头都是未匹配的点的交替路。只有可能两边都是匹配点的交替链或者只有一端是未匹配点的交替链。
1.对于两边都已匹配的情况,不论怎么变化关系,匹配数都会减少,所以这种交替链中所有的点都是关键点。
2.对于只有一边匹配的情况,可以通过一些匹配边的改变使得中间一些点不在最大匹配中,那么哪些点可以变成非匹配点呢?发现只有和最开始的那个未匹配的点在同一边的点才可以变成非匹配点(大概是因为奇偶性吧)。
所以对于左边或者右边的点,我们只要从未匹配的点出发,走到的所有的和这个未匹配的点在一边的点都打上标记,表示都不是关键点,其余的都是关键点了。

/*=================================
 * Author : ylsoi
 * Problem : bzoj3546 life of the party
 * Algorithm : Graph Matching
 * Time : 2018.5.27
 * ==============================*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<climits>
using namespace std;
void File(){
    freopen("bzoj3546.in","r",stdin);
    freopen("bzoj3546.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf INT_MAX
const int maxn=1e4+10;
const int maxk=1e5+10;
int n,m,k,beg[maxn][2],cnt[2],a[maxn],b[maxn];
bool vis[maxn];
struct edge{int to,last;}E[maxk][2];
void add(int u,int v,bool ty){
    ++cnt[ty];
    E[cnt[ty]][ty].to=v;
    E[cnt[ty]][ty].last=beg[u][ty];
    beg[u][ty]=cnt[ty];
}
bool dfs(int u){
    for(int i=beg[u][0];i;i=E[i][0].last){
        int v=E[i][0].to;
        if(vis[v])continue;
        vis[v]=1;
        if(!b[v] || dfs(b[v])){
            a[u]=v;
            b[v]=u;
            return true;
        }
    }
    return false;
}
void find1(int u){
    vis[u]=1;
    for(int i=beg[u][0];i;i=E[i][0].last){
        int v=E[i][0].to;
        if(b[v]==u)continue;
        if(vis[b[v]])continue;
        find1(b[v]);
    }
}
void find2(int u){
    vis[u]=1;
    for(int i=beg[u][1];i;i=E[i][1].last){
        int v=E[i][1].to;
        if(a[v]==u)continue;
        if(vis[a[v]])continue;
        find2(a[v]);
    }
}
int main(){
    File();
    scanf("%d%d%d",&n,&m,&k);
    REP(i,1,k){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v,0);
        add(v,u,1);
    }
    REP(i,1,n){
        dfs(i);
        mem(vis);
    }
    REP(i,1,n)if(!a[i])
        find1(i);
    REP(i,1,n)if(!vis[i])
        printf("%d\n",i);
    mem(vis);
    REP(i,1,m)if(!b[i])
        find2(i);
    REP(i,1,m)if(!vis[i])
        printf("%d\n",i);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/80467889
今日推荐