染色配对(详解+代码)

来源:互联网 发布:老虎证券 财报数据 编辑:程序博客网 时间:2024/05/02 12:04

Description

这里写图片描述
(说实话我也不知道这图片是什么)

Solution

然而在这里我还是比较有必要讲一下题意的

定义一种东西叫团,可以看作每个团都是一个完全图
定义极大团是指没有比自己更大的团包含自己
给你N个点,M个极大团组成的一个无向图,已知每个点都在刚好两个极大团中

求这个图的极大匹配(就是两两点连边,每个点最多是一条边的端点)个数及匹配方案(任意输出)

因为这个图并没有直接给出点与点之间的关系,所以我们不妨把每个极大团设为一个大点(为了区分,我们把新图中的点也就是原来的极大团称为大点,原图中的点称为小点),由于每个小点都是属于刚好两个极大团的,所以小点就是新图中的边

显然,一个极大团中的小点都是可以两两匹配的。
size[i]表示第i个极大团中的小点个数(也就是新图中连向第i个大点的边的个数)

对于新图中的每一个联通块,我们都做一个DFS,对于每个联通块组成的搜索树
这里写图片描述
(边上是边的编号,也就是小点的编号)

极大匹配小点也就是极大匹配两条相邻的边

从底部回溯上来时,我们看这个大点还有多少条边(size)没有匹配

如果是偶数,那就两两匹配

如果是奇数,那就把多出来的那一个留给他父亲,让他父亲来选择匹配

自己在图上模拟一下……就容易理解了

注意每匹配一条边相应size要减掉

可以发现一个奇妙的性质

对于新图每一个联通块,它的极大匹配个数就是联通块size[i]2
因为每一个点都可以推给他父亲

Code

#include<cstdio>#include<cstdlib>#include<algorithm>#include<iostream>#include<cstring>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;struct note{    int x,y,z;};bool cmp(note x,note y){    return x.x<y.x;}int n,m,a1[20001][2],pr[100001][2],ans,size[20001];note pt[400002];bool bz[20001],b[200001];void match(int x,int y){    pr[++ans][0]=pt[x].z;    pr[ans][1]=pt[y].z;    b[pt[x].z]=1;    b[pt[y].z]=1;    size[pt[x].x]--;    size[pt[x].y]--;    size[pt[y].x]--;    size[pt[y].y]--;}void find(int k,int f){    int i,j,sz=size[k];    bool bzl=1;    if (a1[k][0]!=0)    {        i=a1[k][0];        while (i<=a1[k][1]&&(b[pt[i].z]||(pt[i].y==f&&sz%2!=0&&bzl)))         {            if (pt[i].y==f&&sz%2!=0&&bzl) bzl=0;            i++;        }        j=i+1;        while (j<=a1[k][1])        {            while (j<=a1[k][1]&&(b[pt[j].z]||(pt[j].y==f&&sz%2!=0&&bzl)))             {                if (pt[j].y==f&&sz%2!=0&&bzl) bzl=0;                j++;            }            if (j<=a1[k][1])            {                match(i,j);            }            i=j+1;            while (i<=a1[k][1]&&(b[pt[i].z]||(pt[i].y==f&&sz%2!=0&&bzl)))             {                if (pt[i].y==f&&sz%2!=0&&bzl) bzl=0;                i++;            }            j=i+1;        }    }}void dfs(int k,int f){    int i;    if (a1[k][0]!=0)    {        fo(i,a1[k][0],a1[k][1])        {            if (bz[pt[i].y]==0)            {                bz[pt[i].y]=1;                dfs(pt[i].y,k);            }        }    }    find(k,f);}int main(){    cin>>m>>n;    int i;    fo(i,1,n)    {        scanf("%d%d",&pt[2*i-1].x,&pt[2*i-1].y);        pt[2*i-1].z=i;        pt[2*i].x=pt[2*i-1].y;        pt[2*i].y=pt[2*i-1].x;        pt[2*i].z=i;    }    sort(pt+1,pt+2*n+1,cmp);    fo(i,1,2*n)    {        size[pt[i].x]++;        if (pt[i].x!=pt[i-1].x)        {            a1[pt[i-1].x][1]=i-1;            a1[pt[i].x][0]=i;        }    }    a1[pt[2*n].x][1]=2*n;    ans=0;    fo(i,1,m)    {        if (!bz[i])        {            bz[i]=1;            dfs(i,0);        }    }    cout<<ans<<endl;    fo(i,1,ans)    {        printf("%d %d\n",pr[i][0],pr[i][1]);    }}
1 0
原创粉丝点击