题意:问给出的图是不是二分图,如果是输出最大匹配,不是输出"No"。
可以利用BFS对图染色来判断一个图是否为二分图。
首先图上各节点为无色的,任选一个未染色节点将其染上红色,然后以该点为原点进行BFS。
从队列中取出点P,若P为红色,则将与其直接相连的点染上蓝色,否则染上红色。若与P直接
相连的点已染色且与P颜色相同,则此图存在奇回路,即不是二分图,BFS终止。
若直到所有点均被染上色且未触发终止条件,则说明此图为二分图。
二分图的最大匹配。
定义:给出一个二分图,找到一个边数最大的匹配,即尽量多的边,使得任意两条选中的边没有公共点。
增广路算法。
增广路定义:终点和起点(两点不相同)均为未盖点(未匹配的点)且 只有这两个点为未盖点 且 路上的已盖点的数量不为奇数 的路称为增广路。
算法描述:
每次选择一个新的未盖点为起点寻找增广路,若找到则匹配数加一,若找到则路上的所有点均标记为已匹配点。
寻找过程:从一个未盖点开始,若与其直接相连的点中有未盖点则找到一条增广路,寻找结束。
若没有则选择一个已盖点A,然后选择与A匹配的点B,若与B直接相连的点中有未盖点,则找到一条增广路,寻找结束。
若没有,则选择一个新的已盖点作为A,A的匹配点为B,再从与B直接相连的点中寻找未盖点。
以此类推,直到找不出新的A或找到了一个未盖点,前者表示没有找到一条增广路,后者反之。
下面说一下自己对增广路的理解:
因为增广路上的只有起点和终点为未盖点,且所有的点的个数为偶数,所以可以让第 i(i为奇数) 个点 与 第(i+1)个点匹配,这样就会多出一次匹配。
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <stack> #pragma comment(linker, "/STACK:1024000000"); #define LL long long int using namespace std; struct N { int v; N *next; }*head[200]; N *creat() { N *p = (N *)malloc(sizeof(N)); p->next = NULL; return p; } bool mark[210]; int color[210]; int Match_Point[210]; bool dfs(int t) { for(N *p = head[t]->next; p != NULL; p = p->next) { if(mark[p->v] == false) { mark[p->v] = true; if(Match_Point[p->v] == -1 || dfs(Match_Point[p->v])) { Match_Point[p->v] = t; Match_Point[t] = p->v; return true; } } } return false; } bool bfs(int n) { queue<int> q; int s,i; N *p; for(i = 1;i <= n; ++i) { if(color[i] == -1) { q.push(i); color[i] = 0; while(q.empty() == false) { s = q.front(); q.pop(); for(p = head[s]->next; p != NULL; p = p->next) { if(color[p->v] == -1) { color[p->v] = (color[s] == 1 ? 0 : 1); q.push(p->v); } else if(color[p->v] == color[s]) { return true; } } } } } return false; } int Cal_Maximal_Matching(int n) { int i,ans = 0; memset(Match_Point,-1,sizeof(Match_Point)); for(i = 1;i <= n; ++i) { if(Match_Point[i] == -1) { memset(mark,false,sizeof(mark)); if(dfs(i)) ans++; } } return ans; } int main() { int i,n,m,u,v; N *p; for(i = 0;i <= 200 ; ++i) { head[i] = creat(); } while(scanf("%d %d",&n,&m) != EOF) { for(i = 1;i <= n; ++i) { head[i]->next = NULL; } while(m--) { scanf("%d %d",&u,&v); p = creat(); p->v = v; p->next = head[u]->next; head[u]->next = p; p = creat(); p->v = u; p->next = head[v]->next; head[v]->next = p; } memset(color,-1,sizeof(color)); if(bfs(n))//说明不是二分图 { cout<<"No"<<endl; } else { printf("%d\n",Cal_Maximal_Matching(n)); } } return 0; }