hdu Uncle Tom's Inherited Land*(1*2矩阵覆盖,最大匹配)

http://acm.hdu.edu.cn/showproblem.php?pid=1507


大致题意:在一个n*m的格子上,黑色的地方不可用,问在白色格子上最多可放多少1*2的矩阵。


思路:建图,每个白色格子与它临近的上下左右的白色格子建边,求最大匹配,答案为最大匹配/2,因为是双向图。最后输出匹配边时,当找到一组匹配边记得将该边标记,以防重复计算。


#include <stdio.h>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#define LL long long
#define _LL __int64
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 110;

int n,m,k;
vector <int> edge[maxn];
int Map[maxn][maxn];
int match[10010],chk[10010];
int cnt;

int addre[10010];
void debug()
{
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= m; j++)
			printf("%d%d ",Map[i][j],addre[Map[i][j]]);
		printf("\n");
	}
}
int dfs(int p)
{
    for(int i = 0; i < (int)edge[p].size(); i++)
    {
        int q = edge[p][i];
        if(!chk[q])
        {
            chk[q] = 1;
            if(match[q] == -1 || dfs(match[q]))
            {
                match[q] = p;
                return 1;
            }
        }
    }
    return 0;
}

void output()
{
	int vis[10010];
	int x,y,xx,yy,tmp;
	memset(vis,0,sizeof(vis));

	for(int i = 1; i <= cnt; i++)
	{
		if(match[i] != -1 && !vis[i])
		{
			tmp = match[i];
			if(!vis[tmp] && i != tmp)
			{
				vis[i] = 1;
				vis[tmp] = 1;
				xx = addre[tmp]/m+1;
				yy = addre[tmp]%m+1;
				x = addre[i]/m+1;
				y = addre[i]%m+1;
				printf("(%d,%d)--(%d,%d)\n",x,y,xx,yy);
			}
		}
	}
}

int main()
{
    int u,v;
    while(~scanf("%d %d",&n,&m) && (n || m))
    {
        for(int i = 1; i <= n*m; i++)
            edge[i].clear();
        memset(Map,-1,sizeof(Map));
        scanf("%d",&k);

        for(int i = 0; i < k; i++)
        {
            scanf("%d %d",&u,&v);
            Map[u][v] = 0;
        }

        cnt = 0;
        int tmp = -1;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
            	tmp++;
                if(Map[i][j] < 0)
                {
                    cnt++;
                    addre[cnt] = tmp;
                    Map[i][j] = cnt;
                }
            }
        }
        //debug();

        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                if(Map[i][j] == 0) continue;
                if(i-1 >= 1 && Map[i-1][j]>0)
                    edge[Map[i][j]].push_back(Map[i-1][j]);
                if(i+1 <= n && Map[i+1][j]>0)
                    edge[Map[i][j]].push_back(Map[i+1][j]);
                if(j-1 >= 1 && Map[i][j-1]>0)
                    edge[Map[i][j]].push_back(Map[i][j-1]);
                if(j+1 <= m && Map[i][j+1]>0)
                    edge[Map[i][j]].push_back(Map[i][j+1]);
            }
        }

        memset(match,-1,sizeof(match));
        int ans = 0;
        for(int i = 1; i <= cnt; i++)
        {
            memset(chk,0,sizeof(chk));
            ans += dfs(i);
        }
        printf("%d\n",ans/2);
		output();
    }

    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值