转自:xdd
xdd博客
说说二分图,其实图论的题难点不在用算法,难在如何建图,只有图建好了,剩下的就简单了,在这说说求二分图的算法,即匈牙利算法,其实一点都不难,也很好理解拿笔写写就行了.
二分图最大匹配—-匈牙利算法
重要的一点就是看出来了用二分图做,然后就是建图了,再然后适当修改Find函数就行了.
int n,m;
int link[1001];
bool vis[1001];
vector<int>data[1001];
bool Find(int x)
{
for(int i=0;i<data[x].size();i++){
int m=data[x][i];
if(!vis[m]){
vis[m] = true;
if(!link[m] || Find(link[m])){
link[m] = x;
link[x] = m;
return true;
}
}
}
return false;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
模板题
AC代码:
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define CLR(x) memset(x,0,sizeof(x))
int n,m;
int link[1001];
bool vis[1001];
vector<int>data[1001];
bool Find(int x)
{
for(int i=0;i<data[x].size();i++){
int m=data[x][i];
if(!vis[m]){
vis[m] = true;
if(!link[m] || Find(link[m])){
link[m] = x;
link[x] = m;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
CLR(link);
int ans=0;
for(int i=0;i<m;i++){
int u,v;
scanf("%d%d",&u,&v);
data[u].push_back(v);
data[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
CLR(vis);
if(!link[i] && Find(i))
ans++;
}
printf("%d\n", ans);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
这里有些重要的定理,有许多题经过建图后发现就是求这些,故常常配合着这个二分图来运算需要记住!!!
(通过一些小的改变即可达到要求)
定理:
定理1:最大匹配数M = 最小点覆盖数
定理2:最大独立集 = 顶点数 - 最大匹配数
定理3:有向图最小路径覆盖数 = 顶点数 - 最大匹配数
定理4:无向图最小路径覆盖数 = 顶点数 - 最大匹配数/2
(因为处理过两次)
对以上名词的一些解释:
最大匹配数:最大匹配的匹配边的数目
最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
最大独立集:选取最多的点,使任意所选两点均不相连
最小路径覆盖数:对于一个 DAG (有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0 (即单个点).
证明略.
二分图判定—-染色法
模板题在此
染色法判断是否是二分图.
AC代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define CLR(x) memset(x,0,sizeof(x))
const int maxn=1e4+5;
int cas=1;
bool flag;
int n,m;
bool vis[maxn][maxn];
vector<int>ve[maxn];
int color[maxn];
void dfs(int x,int col)
{
if(!flag) return ;
if(!color[x]) color[x]=col;
else if(color[x]!=col){
flag=false;
return ;
}
for(int i=0;i<ve[x].size();i++)
{
int next=ve[x][i];
if(!vis[x][next] && !vis[next][x]){
vis[x][next]=1;
dfs(next,3-col);
}
}
}
int main()
{
int t;
cin >> t;
while(t--){
flag=true;
scanf("%d %d",&n,&m);
CLR(color);
CLR(vis);
for(int i=1;i<=n;i++)
ve[i].clear();
for(int i=0;i<m;i++){
int u,v;
scanf("%d %d",&u,&v);
ve[u].push_back(v);
ve[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
if(!color[i]) dfs(i,1);
}
if(flag) printf("Correct\n");
else
printf("Wrong\n");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57