URAL1099-Work Scheduling(一般图最大匹配(带花树))

来源:互联网 发布:淘宝怎么修改差评? 编辑:程序博客网 时间:2024/06/09 08:12

题目来源:https://et/problem/URAL-1099

题意

给出一个一般有向图,求最大匹配,并且把最大匹配的点数输出,以及匹配额点。。。

思路

最大匹配分为二分图最大匹配和一般图最大匹配,利用匈牙利算法或者HK算法可解,一般图最大匹配利用带花树算法可解(缩花,开花)(并查集证明是同一朵花,最近公共祖先找花。)
在增广路径的过程中,利用深搜的原理生成搜索树,假如称离根节点有偶数条边的点为偶点,称离根节点有奇数条边的点为奇点,那么假设已匹配点称为S,待匹配点称为T,也即是说偶点是S,奇点是T:
对于二分图来讲:
递归找到一个T,便可以增广路径,也即是S–>T(S可以到T),也就是偶点到奇点。
对于一个一般图来讲:
递归找到一个T,同样可以增广路径,但是他还有另外一种情况:偶点到偶点,也就是一个点出现两次,并且距离都是偶数条边,如果在这棵树上两个偶点连一条边,那么从树根到这两个偶点里面的任意一个点都可以是偶点(就成了花),也就是这一般图中,所覆盖的点可以整体看成一个偶点(缩花),利用并查集,以及LCA操作进行缩花,然后就会清除这种偶点到偶点的情况。。。
推荐博客:http://www.csie.ntnu.edu.tw/~u91029/

代码

//裸模板#include<cmath>#include<vector>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=230;int n;int pre[maxn];int finds(int x){    return pre[x]==x?x:pre[x]=finds(pre[x]);}void unit(int x,int y){    int fx=finds(x);    int fy=finds(y);    if(fx!=fy)        pre[fx]=fy;}int match[maxn],nexx[maxn],vis[maxn],mark[maxn],Q[maxn],rear;int LCA(int x,int y){    static int t=0;t++;    while(1)    {        if(x!=-1)        {            x=finds(x);            if(vis[x]==t)//如果把t直接改成1,就会超时。。不知道是为啥                return x;            vis[x]=t;            if(match[x]!=-1) x=nexx[match[x]];            else x=-1;        }        swap(x,y);    }}void group(int x,int y){    while(x!=y)    {        int a=match[x],b=nexx[a];        if(finds(b)!=y) nexx[b]=a;        if(mark[a]==2) mark[Q[++rear]=a]=1;        if(mark[b]==2) mark[Q[++rear]=b]=1;        unit(x,a);        unit(a,b);        x=b;    }}vector<int> v[maxn];void ex_load(int s){    memset(vis,0,sizeof(vis));    memset(mark,0,sizeof(mark));    memset(nexx,-1,sizeof(nexx));    for(int i=1;i<=n;i++) pre[i]=i;    mark[s]=1;    Q[0]=s,rear=0;    for(int front=0;match[s]==-1&&front<=rear;front++)    {        int x=Q[front];        for(int i=0;i<(int)v[x].size();i++)        {            int y=v[x][i];            if(match[x]==y) continue;            if(finds(x)==finds(y)) continue;            if(mark[y]==2) continue;            if(mark[y]==1)            {                int r=LCA(x,y);                if(finds(x)!=r) nexx[x]=y;                if(finds(y)!=r) nexx[y]=x;                group(x,r);                group(y,r);            }            else if(match[y]==-1)            {                nexx[y]=x;                int u=y;                while(u!=-1)                {                   int v=nexx[u];                   int tmp=match[v];                   match[u]=v,match[v]=u;                   u=tmp;                }                break;            }            else            {                nexx[y]=x;                mark[Q[++rear]=match[y]]=1;                mark[y]=2;            }        }    }}bool g[maxn][maxn];int main(){    scanf("%d",&n);    memset(g,0,sizeof(g));    int x,y;    while(~scanf("%d%d",&x,&y))    {        if(x!=y&&!g[x][y])        {            v[x].push_back(y);            v[y].push_back(x);            g[x][y]=g[y][x]=1;        }    }    memset(match,-1,sizeof(match));    for(int i=1;i<=n;i++)    {        if(match[i]==-1)            ex_load(i);    }    int ans=0;    for(int i=1;i<=n;i++)    {        if(match[i]!=-1)            ans++;    }    printf("%d\n",ans);    for(int i=1;i<=n;i++)    {        if(match[i]>i)        {            printf("%d %d\n",i,match[i]);        }    }    return 0;}
阅读全文
0 0
原创粉丝点击