有关二分图匹配的两个例题及思考

第一个例题:POJ3041
题目链接:Asteroids
题目的大概意思是:每一行、每一列都有一些障碍物,你每次可以扫清一行或者一列的障碍物,求你最少的操作数。
用二分图去解决,可以这样去想:将每一行当作二分图的左边节点,将每一列当作二分图的右节点,当一行与一列的交点有障碍物时,将两个的节点连成一条线。所以题目就变成了求覆盖所有的边(所有障碍物),需要的最少的节点的个数。也就是最小点覆盖问题,在二分图中,最小点覆盖即为最大匹配数。
代码如下:

/*************************************************************************
    > File Name: main.cpp
    > Author:Eagles 
    > Mail:None 
    > Created Time: 2018年09月14日 星期五 18时46分23秒
    > Description:POJ3041,最小顶点覆盖 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define N 600
struct node
{
    int to;
    int nex;
}E[N*N];
int head[N];
int pre[N];
bool vis[N];
int n,cnt,k;

void addEdge(int a, int b)
{
    E[cnt].to=b;
    E[cnt].nex=head[a];
    head[a]=cnt++;
}

void init()
{
    memset(head,-1,sizeof(head));
    memset(pre,-1,sizeof(pre));
    cnt=0;
    for (int i=0; i<k; i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        addEdge(a-1,b-1);
    }
}

int dfs(int x)
{
    for (int i=head[x]; i!=-1; i=E[i].nex)
    {
        if (!vis[E[i].to])
        {
            vis[E[i].to]=true;

            if (pre[E[i].to]==-1||dfs(pre[E[i].to]))
            {
                pre[E[i].to]=x;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    while (~scanf("%d%d",&n,&k))
    {
        init();
        int sum=0;

        for (int i=0; i<n; i++)
        {
            memset(vis,false,sizeof(vis));
            if (dfs(i))
                sum++;
        }

        printf("%d\n",sum);
    }
    return 0;
}

第二个例题:POJ2226
题目链接:Muddy Fields
题目乍一看,跟上面差不多,然后我毫不犹豫地按照上面的思路做了,提交之后就wa了…
仔细对比题目,就会发现,上一题是一整行或一整列都可以扫清,而这一题只是扫清一行或一列中连续的部分,这就是二者的差别。第一个例题中,一行或一列可以代表整个一行或一列,而这道题一行中如果出现不连续的两段或者两段以上,那么需要的节点数就大于1,所以就不能单纯地用行号或列号去代表二分图左边或者右边的节点。所以这道题构图的时候,将连续的地方用一个节点代替,剩下的就跟第一题一样了。
详见代码:

/*************************************************************************
    > File Name: main.cpp
    > Author:Eagles 
    > Mail:None 
    > Created Time: 2018年09月14日 星期五 19时51分30秒
    > Description:POJ2226 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define N  2000
struct node
{
    int to;
    int nex;
}E[N*N];
int head[N];
bool vis[N];
int pre[N];
int r,c,cnt;
char map[N][N];
int col[N][N],row[N][N];
int co,ro;

void addEdge(int a, int b)
{
    E[cnt].to=b;
    E[cnt].nex=head[a];
    head[a]=cnt++;
}

void init()
{
    memset(head,-1,sizeof(head));
    memset(pre,-1,sizeof(pre));
    memset(row,0,sizeof(row));
    memset(col,0,sizeof(col));
    cnt=ro=co=0;

    for (int i=1; i<=r; i++)
    {
        for (int j=1; j<=c; j++)
        {
            cin>>map[i][j];
        }
    }

    for (int i=1; i<=r; i++)
    {
        for (int j=1; j<=c; j++)
        {
            if (map[i][j]=='*')
            {
                if (row[i][j-1])
                    row[i][j]=row[i][j-1];
                else
                    row[i][j]=++ro;

                if (col[i-1][j])
                    col[i][j]=col[i-1][j];
                else
                {
                    col[i][j]=++co;
                }
            }
        }
    }

    for (int i=1; i<=r; i++)
    {
        for (int j=1; j<=c; j++)
        {
            if (map[i][j]=='*')
            {
                addEdge(row[i][j],col[i][j]);
            }
        }
    }
}
int dfs(int x)
{
    for (int i=head[x]; i!=-1; i=E[i].nex)
    {
        if (!vis[E[i].to])
        {
            vis[E[i].to]=true;

            if (pre[E[i].to]==-1||dfs(pre[E[i].to]))
            {
                pre[E[i].to]=x;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    while (~scanf("%d%d",&r,&c))
    {
        init();
        int sum=0;
        for (int i=1; i<=ro; i++)
        {
            memset(vis,false,sizeof(vis));
            if (dfs(i))
                sum++;
        }

        printf("%d\n",sum);
    }
    return 0;
}
发布了45 篇原创文章 · 获赞 2 · 访问量 3088

猜你喜欢

转载自blog.csdn.net/wysiwygo/article/details/82710193