一般图最大匹配(UOJ-79)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011815404/article/details/90048144

Problem Description

从前一个和谐的班级,所有人都是搞OI的。有 n 个是男生,有 0 个是女生。男生编号分别为 1,…,n。

现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽。每个人至多属于一个小组。

有若干个这样的条件:第 v 个男生和第 u 个男生愿意组成小组。

请问这个班级里最多产生多少个小组?

Input

第一行两个正整数,n,m。保证 n≥2。

接下来 m 行,每行两个整数 v,u 表示第 v 个男生和第 u 个男生愿意组成小组。保证 1≤v,u≤n,保证 v≠u,保证同一个条件不会出现两次。

Output

第一行一个整数,表示最多产生多少个小组。

接下来一行 n 个整数,描述一组最优方案。第 v 个整数表示 v 号男生所在小组的另一个男生的编号。如果 v 号男生没有小组请输出 0。

Examples

Input

10 20
9 2
7 6
10 8
3 9
1 10
7 1
10 9
8 6
8 2
8 1
3 1
7 5
4 7
5 9
7 8
10 4
9 1
4 8
6 3
2 5

Output

5
9 5 6 10 2 3 8 7 1 4

Input

5 4
1 5
4 2
2 1
4 3

Output

2
2 1 4 3 0

思路:一般图匹配模版题

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
const int MOD = 1E9+7;
const int N = 500+5;
const int dx[] = {0,0,-1,1,-1,-1,1,1};
const int dy[] = {-1,1,0,0,-1,1,-1,1};
using namespace std;

struct Edge {
    int v,next;
} edge[N*N*2];
int n,m;
int head[N],tot;
int father[N],pre[N];//father记录一个点属于哪个一个点为根的花
int match[N],type[N];//type记录一个点为奇点/偶点,1为奇,2为偶
int vis[N],timeBlock;
int Q[N*N*2],first,tail;

void addEdge(int u,int v) {//添边
    edge[++tot].v=v;
    edge[tot].next=head[u];
    head[u]=tot;
}
int Find(int x){//并查集寻找根节点
    if(father[x]!=x)
        return father[x]=Find(father[x]);
    return father[x];
}
int LCA(int x,int y) {//求解最近公共祖先
    timeBlock++;
    while(vis[x]!=timeBlock) {
        if(x) {
            x=Find(x);
            if(vis[x]==timeBlock)
                return x;
            vis[x]=timeBlock;
            if(match[x]!=0)
                x=Find(pre[match[x]]);
            else x=0;
        }
        swap(x,y);
    }
    return x;
}
void shrink(int x,int y,int k) {//将奇环缩成一个点并将原来是奇点的点变为偶点并加入队列
    while(Find(x)!=k) {
        pre[x]=y;
        int z=match[x];
        if(type[z]==1) {
            type[z]=0;
            Q[++tail]=z;
        }
        if(Find(z)==z)
            father[z]=k;
        if(Find(x)==x)
            father[x]=k;
        y=z;
        x=pre[y];
    }
}
bool bfs(int s) {
    for(int i=1; i<=n; i++)
        father[i]=i;
    memset(type,0,sizeof(type));
    memset(pre,0,sizeof(pre));

    first=tail=1;
    Q[first]=s;
    type[s]=1;

    int t=0;
    while (first<=tail) {
        int x=Q[first++];
        int y=edge[head[x]].v;
        for(int i=head[x]; i; i=edge[i].next) {
            if(Find(y)==Find(x) || type[y]==2)
                continue;

            if(!type[y]) {
                type[y]=2;
                pre[y]=x;
                if(!match[y]) {
                    int last;
                    for(int now=y; now; now=last) {
                        int temp=pre[now];
                        last=match[temp];
                        match[now]=temp;
                        match[temp]=now;
                    }
                    return true;
                }
                type[match[y]]=1;
                Q[++tail]=match[y];
            }
            else if (type[y]==1) {
                int k=LCA(x,y);
                shrink(x,y,k);
                shrink(y,x,k);
            }
            y=edge[i].v;
        }
    }
    return false;
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        addEdge(x,y);
        addEdge(y,x);
    }

    int res=0;
    for(int i=1; i<=n; i++)
        res+=(!match[i] && bfs(i));
    printf("%d\n",res);
    for(int i=1; i<=n; i++)
        printf("%d ",match[i]);
    printf("\n");
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u011815404/article/details/90048144