poj2446 Chessboard 二分图最大匹配 思考 匈牙利算法BFS实现

来源:互联网 发布:红蜻蜓软件 编辑:程序博客网 时间:2024/05/19 15:41

                                POJ 2446 点击打开链接

大致题意:

有一个m*n棋盘,上面有k个洞,你现在有许多个规模为1*2的小卡片。你可以将卡片覆盖在棋盘上(卡片必须整个覆盖在棋盘上),正好覆盖一个1*2的空间,但是不能覆盖有洞的棋盘格子。问,你是否能用一些卡片不限个数),将棋盘的无洞格子全都覆盖

例如:

(1):

它是合法的,全部覆盖。

(2)


不合法,因为有一个洞被覆盖了。

(3)


不合法,因为有一个正常的格子没被覆盖。

大致思路:

我们将二维状态转换成一维状态,将棋子编号为1,2,3.....n*m。将这些棋子放在一个集合里,然后将它们的相邻棋子放在另一个集合里。然后能与之相邻的进行连接,这样就构成了二分图。然后寻找最大匹配数(当然,在之前,我们一定将有洞的格子和正常的格子进行了分类),最大匹配数意味着可以找到1*2的空间的最大数。既然我们找到了最大匹配,我们看是否等于n*m-k,是的话,代表我们能成功。

代码:

#include<stdio.h>#include<iostream>#include<string.h>#include<vector>#include<queue>#include<map>using namespace std;typedef pair<int,int>Pa;map<Pa,int>M;int vis[1505],pre[1505];int ml[1505],mr[1505];int flag[1505];//用来区分有洞和无洞的格子vector<int>V[1505];int m,n,k;int MaxMatch()//bfs匈牙利算法寻找最大匹配数{    int sum=0;    memset(ml,-1,sizeof(ml));    memset(mr,-1,sizeof(mr));    memset(vis,0,sizeof(vis));    for(int i=1; i<=n*m; i++)    {        if(!flag[i]&&ml[i]==-1)//这个棋子不是匹配点而且没洞        {                   //寻找增广路            queue<int>Q;            Q.push(i);            pre[i]=-1;            int kas=0;            while(!Q.empty()&&!kas)            {                int st=Q.front();                Q.pop();                for(int j=0; j<V[st].size()&&!kas; j++)                {                    int to=V[st][j];                    if(vis[to]!=i&&!flag[to])                    {                        vis[to]=i;                        Q.push(mr[to]);                        if(mr[to]>=0)                        {                            pre[mr[to]]=st;                        }                        else                        {                            kas=1;                            int d=st,e=to;                            while(d!=-1)                            {                                int temp=ml[d];                                ml[d]=e;                                mr[e]=d;                                e=temp;                                d=pre[d];                            }                        }                    }                }            }            if(kas)sum++;        }    }    return sum;}int main(){    while(~scanf("%d%d%d",&m,&n,&k))    {        memset(flag,0,sizeof(flag));        M.clear();        int x,y;        for(int i=0; i<k; i++)        {            scanf("%d%d",&x,&y);            M[make_pair(y,x)]=1;//将有洞的格子的二维坐标进行标记        }        int ans=1;//棋子编号从1开始        for(int i=1; i<=m; i++)//便利整个棋盘,我们要将二维棋盘转化成一维的,利于操作        {            for(int j=1; j<=n; j++)            {                if(!M[make_pair(i,j)])//这个棋子是正常的                {                    if(j<n)   //将此时的棋子与其相邻的棋子进行“画边”                    {                        V[ans].push_back(ans+1);                    }                    if(j>1)                    {                        V[ans].push_back(ans-1);                    }                    if(i<m)                    {                        V[ans].push_back(ans+n);                    }                    if(i>1)                    {                        V[ans].push_back(ans-n);                    }                    ans++;                }                else                {                    flag[ans]=1;//这个编号的棋子是有洞的                    ans++;                }            }        }        /*for(int i=1; i<=n*m; i++)        {            if(flag[i])continue;            printf("%d:\n",i);            for(int j=0; j<V[i].size(); j++)            {                printf("%2d",V[i][j]);            }            printf("\n");        }*/        int he=MaxMatch();        if(he+k==n*m)        {            printf("YES\n");        }        else            printf("NO\n");    }}