二分图 最大匹配 hdu 2063 poj 2226

二分图的基本概念 一个无向图G=<V, E>,如果存在两个集合X、Y,使得X∪Y=V, X∩Y=Φ,并且每一条边e={x,y}有x∈X,y∈Y,则称G为一个二分图(bipartite graph)。常用<X, E, Y>来表示一个二分图。若对X中任一x及Y中任一y恰有一边e∈E,使e = {x, y}, 则称G为完全二分图(complete bipartite graph)。当|X| = m,|Y| = n时,完全二分图G记为Km,n

二分图的性质: 定理:无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。 匹配:设G=<V, E>为二分图,如果M⊆E,并且M中没有任何两边有公共端点。M=Φ时称M为空匹配。 最大匹配:G的所有匹配中边数最多的匹配称为最大匹配。 完全匹配:若X(Y)中所有的顶点都是匹配M中的端点。则成M为完全匹配。若M既是X-完全匹配又是Y-完全匹配,则称M为G的完全匹配。 注意:最大匹配总是存在但未必唯一;X(Y)-完全匹配及G的完全匹配必定是最大的,但反之则不然;X(Y)-完全匹配未必存在。

下面引入几个术语: 设G=<V, E>为二分图,M为G的一个匹配。

  1. M中边的端点称为M-顶点,其它顶点称为非M-顶点
  2. 增广路径:除了起点和终点两个顶点为非M-顶点,其他路径上所有的点都是M=顶点。而且它的边为匹配边、非匹配边交替出现。

hdu 2063 过山车  简单的二分图最大匹配

   题目连接:  http://acm.hdu.edu.cn/showproblem.php?pid=2063

                   http://poj.org/problem?id=2226

代码如下:

#include <iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 510
bool flag[MAX];
int map[MAX][MAX],mark[MAX];
int k,b,g;
bool dfs(int x)
{

    for(int i=1;i<=b;i++)
    {
        if(!map[x][i]||flag[i])//如果这两点没边 或有边但被标记过了就继续循环
            continue;
        flag[i]=1;   
        if(!mark[i]||dfs(mark[i])) //如果该点是孤立点或者不是孤立点时就搜索该点对应女生的增广路
        {
            mark[i]=x;
            return 1;
        }
    }
    return 0;
}
int find()
{
    int i,sum=0;
    memset(mark,0,sizeof(mark));
    for(i=1;i<=g;i++)
    {
        memset(flag,0,sizeof(flag));
        if(dfs(i))
            sum++;
    }
    return sum;
}
int main()
{
    int x,y;
    while(scanf("%d",&k)!=EOF)
    {
        if(k==0) break;
        scanf("%d%d",&g,&b);
        memset(map,0,sizeof(map));
        for(int i=1;i<=k;i++)
            {
                scanf("%d%d",&x,&y);
                map[x][y]=1;
            }
        printf("%d
",find());
    }
    return 0;
}
View Code
//poj 2226
#include <iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 900
bool flag[MAX];
int map[MAX][MAX],mark[MAX],cx[MAX][MAX],cy[MAX][MAX];
char a[MAX][MAX];
int n,m,nx,ny;
bool dfs(int x)
{
    for(int i=1;i<=ny;i++)
    {
        if(!map[x][i]||flag[i])//如果这两点没边 或有边但被标记过了就继续循环
            continue;
        flag[i]=1;
        if(!mark[i]||dfs(mark[i])) //如果该点是孤立点或者不是孤立点时就搜索该点对应女生的增广路
        {
            mark[i]=x;//标记该点连接的边
            return 1;
        }
    }
    return 0;
}
int find()
{
    int i,sum=0;
    memset(mark,0,sizeof(mark));
    for(i=1;i<=nx;i++)
    {
        memset(flag,0,sizeof(flag));
        if(dfs(i))
            sum++;
    }
    return sum;
}
int main()
{
    int i,j;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        getchar();
        for(i=1;i<=n;i++)
        {

            for(j=1;j<=m;j++)
                a[i][j]=getchar();
            getchar();
        }
        nx=ny=0;
        for(i=1;i<=n;i++)
        {
            j=1;
            while(j<=m)
            {
            if(a[i][j]=='*')
            {
                nx++;
                while(a[i][j]=='*')
                    cx[i][j++]=nx;
            }
            else j++;
            }
        }
        for(j=1;j<=m;j++)
        {
            i=1;
            while(i<=n)
            {
            if(a[i][j]=='*')
            {
                ny++;
                while(a[i][j]=='*')
                    cy[i++][j]=ny;
            }
            else i++;
            }
        }
        memset(map,0,sizeof(map));
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
            if(a[i][j]=='*') map[cx[i][j]][cy[i][j]]=1;
        printf("%d
",find());
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/yly921712230/p/3227418.html