题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1507
题意:给一个N*M的矩阵,一个格子表示一块土地,有些土地被改造成了池塘,问现在如果要按1X2的矩形卖掉土地,最多能卖多少块,并输出方案(任一)。
解法:因为是1X2 的矩阵,所以可以用二分图做最大匹配来做,构图时可以将矩阵按行列和的奇偶进行染色,要保证二部图的建立。
代码:
//Hdu 1507 二分图模板。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define maxn 10010
int V;
int G[maxn][5];
bool map[101][101];
class Hungary //模板
{
private:
int cnt;
bool vis[maxn];
public:
int match[maxn];
bool DFS(int u) //搜索增广路
{
for(int v,i = 1; i <= G[u][0]; i++){
v = G[u][i];
if(!vis[v]){
vis[v] = true;
if(match[v] == 0 || DFS(match[v]) ) //如果找到未匹配的结点,则找到了增广路
{
match[v] = u;
return true;
}
}
}
return false;
}
int Hungary_match()
{
cnt = 0;
memset(match,0,sizeof(match));
for(int u=1; u<=V; u++)
{
memset(vis,0,sizeof(vis));
if(DFS(u)) cnt++;
}
return cnt;
}
}H;
int n,m,k;
void makeBG() //奇偶二分建图
{
V = n*m;
for(int i=1; i<=V; i++) G[i][0] = 0;
int u;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
if(map[i][j] && (i+j)%2 == 1) //奇数
{
u = (i-1)*m+j;
if(map[i][j+1])G[u][ ++G[u][0] ] = u+1;
if(map[i][j-1])G[u][ ++G[u][0] ] = u-1;
if(map[i+1][j])G[u][ ++G[u][0] ] = u+m;
if(map[i-1][j])G[u][ ++G[u][0] ] = u-m;
}
}
void init(){
memset(map,1,sizeof(map));
for (int i = 0; i <= n+1; i++)
map[i][0] = map[i][m+1] = 0;
for (int i = 0; i <= m+1; i++)
map[0][i] = map[n+1][i] = 0;
}
int main()
{
while(~scanf("%d%d",&n,&m),n+m)
{
init();
scanf("%d",&k);
int u,v;
while(k--)
{
scanf("%d%d",&u,&v);
map[u][v] = 0;
}
makeBG();
printf("%d\n",H.Hungary_match());
int link[maxn];
memset(link,0,sizeof(link));
for(int i=1; i<=V; i++)
link[ H.match[i] ] = i;
for(int u=1; u<=V; u++)
if(link[u])
{
v = link[u];
//找u,v对应的行和列。
printf("(%d,%d)",(u-1)/m+1,(u-1)%m+1);
printf("--");
printf("(%d,%d)",(v-1)/m+1,(v-1)%m+1);
printf("\n");
}
printf("\n");
}
return 0;
}