Input
Output
Sample
input | output |
---|---|
3 1 2 2 3 1 3 |
2 1 2 |
//
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=250;
int n;//點數(1->n)
int head;
int tail;
int Start;
int Finish;
int link[N]; //表示哪個點匹配了哪個點
int Father[N]; //這個就是增廣路的Father……但是用起來太精髓了
int Base[N]; //該點屬於哪朵花
int Q[N];
bool mark[N];
bool mat[N][N];//鄰接矩陣
bool InBlossom[N];
bool in_Queue[N];
void BlossomContract(int x,int y){
memset(mark,0,sizeof(mark));
memset(InBlossom,0,sizeof(InBlossom));
#define pre Father[link[i]]
int lca,i;
for (i=x;i;i=pre) {i=Base[i]; mark[i]=true; }
for (i=y;i;i=pre) {i=Base[i]; if (mark[i]) {lca=i; break;} } //尋找lca之旅……一定要注意i=Base[i]
for (i=x;Base[i]!=lca;i=pre){
if (Base[pre]!=lca) Father[pre]=link[i]; //對於BFS樹中的父邊是匹配邊的點,Father向後跳
InBlossom[Base[i]]=true;
InBlossom[Base[link[i]]]=true;
}
for (i=y;Base[i]!=lca;i=pre){
if (Base[pre]!=lca) Father[pre]=link[i]; //同理
InBlossom[Base[i]]=true;
InBlossom[Base[link[i]]]=true;
}
#undef pre
if (Base[x]!=lca) Father[x]=y; //注意不能從lca這個奇環的關鍵點跳回來
if (Base[y]!=lca) Father[y]=x;
for (i=1;i<=n;i++)
if (InBlossom[Base[i]]){
Base[i]=lca;
if (!in_Queue[i]){
Q[++tail]=i;
in_Queue[i]=true; //要注意如果本來連向BFS樹中父結點的邊是非匹配邊的點,可能是沒有入隊的
}
}
}
void Change(){
int x,y,z;
z=Finish;
while (z){
y=Father[z];
x=link[y];
link[y]=z;
link[z]=y;
z=x;
}
}
void FindAugmentPath(){
memset(Father,0,sizeof(Father));
memset(in_Queue,0,sizeof(in_Queue));
for (int i=1;i<=n;i++) Base[i]=i;
head=0; tail=1;
Q[1]=Start;
in_Queue[Start]=1;
while (head!=tail){
int x=Q[++head];
for (int y=1;y<=n;y++)
if (mat[x][y] && Base[x]!=Base[y] && link[x]!=y) //無意義的邊
if ( Start==y || link[y] && Father[link[y]] ) //精髓地用Father表示該點是否
BlossomContract(x,y);
else if (!Father[y]){
Father[y]=x;
if (link[y]){
Q[++tail]=link[y];
in_Queue[link[y]]=true;
}
else{
Finish=y;
Change();
return;
}
}
}
}
void Edmonds(){
memset(link,0,sizeof(link));
for (Start=1;Start<=n;Start++)
if (link[Start]==0)
FindAugmentPath();
}
void output(){
memset(mark,0,sizeof(mark));
int cnt=0;//一般圖最大匹配 最大點數
for (int i=1;i<=n;i++)
if (link[i]) cnt++;
printf("%d\n",cnt);
for (int i=1;i<=n;i++)
if (!mark[i] && link[i]){
mark[i]=true;//i和link[i]匹配
mark[link[i]]=true;
printf("%d %d\n",i,link[i]);
}
}
int main(){
int x,y;
scanf("%d",&n);
memset(mat,0,sizeof(mat));
while (scanf("%d%d",&x,&y)!=EOF)
mat[x][y]=mat[y][x]=1;
Edmonds();
output();
return 0;
}