Uncle Tom's Inherited Land*

最大匹配问题  

题意:题目意思:
给定一个  n * m 的矩阵格子, 第二行给定一个k值表示池塘,接下来给出池塘坐标,要求的就是在不是池塘的区域用1 * 2 的小矩形填充它 ,问 最多能填充几个小矩形,并且打印出所有矩阵!

这题拿到手毫无头绪 是这个专题最难的一题了

这题值得多打几遍

#include<bits/stdc++.h>
using namespace std;
#define N 105

int mp[N][N];
int used[N];
int vis[N];
int n,m,r,c;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int flag[N][N];
int ans[N][2];
int cnt;
vector<int>g[N*N];
bool dfs(int  x)
{
    for(int j=0;j<g[x].size();j++)
    {
        if(!used[ g[x][j] ]) //所有的j都改为了g[x][j]
        {
            used[ g[x][j] ]=1;
            if(!vis[ g[x][j] ]||dfs(vis[ g[x][j] ]))
              {
                  vis[ g[x][j] ]=x;
                  return true;
              }
        }
    }
    return false;
}

int find1(void)
{    int ans=0;
      memset(vis,0,sizeof(vis));
     for(int i=1;i<=cnt-1;i++)
       {
           memset(used,0,sizeof(used));
           if(dfs(i))ans++;
       }
       return ans;
}

bool inmap(int x,int y)
{
    if(x>=1&&x<=n&&y>=1&&y<=m)return true;
    else return false;
}

int main()
{
   while(scanf("%d%d",&n,&m),n||m)
   {
       memset(mp,0,sizeof(mp));
       memset(flag,0,sizeof(flag));
       memset(ans,0,sizeof(ans));
       for(int i=0;i<=N*N;i++)g[i].clear();
       int q;
       scanf("%d",&q);
       while(q--)
       {
           int a,b;
           scanf("%d%d",&a,&b);
           mp[a][b]=1;
       }
        cnt=1;
       for(int i=1;i<=n;i++)//扫描各个点  进行离散化
        for(int j=1;j<=m;j++)
           if(mp[i][j]==0)
            {
              ans[cnt][0]=i;
              ans[cnt][1]=j;//这个数组用的巧妙!!
              flag[i][j]=cnt++;//从小到大标记各个有效点
            }
        for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++)
            if(flag[i][j])
             if( 1&(i+j) )//只处理奇数的  可以提高效率 否则的话 ans为两倍(匹配两次) 并且打印各个点就会出错!!很重要
            {
             for(int k=0;k<4;k++)//类似dfs   扫描一个点 将其匹配的点(就是相邻点)存入匹配向量!!!
             {
                int x=i+dx[k];
                int y=j+dy[k];
                 if(inmap(x,y)&&flag[x][y])
                    g[ flag[i][j] ].push_back( flag[x][y] );
             }
            }
       printf("%d\n",find1());
       for(int i=1;i<cnt;i++)//使用vis数组来打印 !这时用上了之前所处理的记录数组
         if(vis[i])
       {
           printf("(%d,%d)--(%d,%d)\n", ans[i][0],ans[i][1],ans[ vis[i] ][0],ans[ vis[i] ][1]  );
       }
      printf("\n");
   }
}

猜你喜欢

转载自www.cnblogs.com/bxd123/p/10372433.html