hdoj 5556 Land of Farms 二分图匹配

合肥赛区的第二简单题
枚举原始农场的重建情况将剩下的点进行最大匹配求得独立集
注意不能连原始农场一起进行匹配,因为会形成有环图不是个二分图

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int flag[105],link[105][105],used[105],n;
int max(int a,int b)
{
    return a>b?a:b;
}
bool dfs(int pre)
{
     for(int i=1;i<=n;i++)
         if(!used[i]&&link[pre][i])
         {
             used[i] = 1;
            if(!flag[i]||dfs(flag[i]))
            {
               flag[i] = pre;
               return true;
            }
         }
         return false;
}
int match()
{
    int ans = 0;
    memset(flag,0,sizeof(flag));
    for(int i=1;i<=n;i++)
    {
        memset(used,0,sizeof(used));
        ans+=dfs(i);
    }
    return ans;
}
int sym[12],ans,mp1[12][12],n1,m1,link2[12][12];
int bu[4][2] = {0,1,0,-1,1,0,-1,0};
char mp[12][12];
void dfs1(int am,int pre)
{
     //建图
     int cnt = 0;
     memset(mp1,0,sizeof(mp1));
     memset(link,0,sizeof(link));
     for(int i=0;i<n1;i++)
         for(int j=0;j<m1;j++)
         if(mp[i][j]=='.')
         {
             bool flag = true;
             for(int k=0;k<4;k++)
             {
                 int x = i+bu[k][0];
                 int y = j+bu[k][1];
                 if(x>=0&&x<n1&&y>=0&&y<m1&&mp[x][y]!='.'&&!sym[mp[x][y]-'0'])
                 {
                     flag = false;
                     break;
                 }
             }
             if(flag)mp1[i][j] = ++cnt;
         }
         n = cnt;

         for(int i=0;i<n1;i++)
             for(int j=0;j<m1;j++)
                 for(int k=0;k<4;k++)
                 {
                     int x = i+bu[k][0];
                     int y = j+bu[k][1];
                     if(x>=0&&x<n1&&y>=0&&y<m1)
                        link[mp1[i][j]][mp1[x][y]] = 1;
                 }
          ans = max(am+n-match()/2,ans);
     // 递归
      for(int i = pre+1;i<=9;i++)
      if(sym[i])
      {
          int flag = true;
          for(int j=0;j<=pre;j++)
             if(!sym[j]&&link2[i][j])
             {
                flag = false;
                break;
             }
          if(flag)
          {
              sym[i] = 0;
              dfs1(am+1,i);
              sym[i] = 1;
          }
      }
}
int main()
{
    int t,i1 = 1;
    scanf("%d",&t);
    while(t--)
    {
       ans = 0;
       scanf("%d%d",&n1,&m1);
       memset(sym,0,sizeof(sym));
       memset(link2,0,sizeof(link2));
       for(int i=0;i<n1;i++)scanf("%s",mp[i]);
       for(int i=0;i<n1;i++)
           for(int j=0;j<m1;j++)
               if(mp[i][j]>='0'&&mp[i][j]<='9') {
                    sym[mp[i][j]-'0'] = 1;
               }
       for(int i=0;i<n1;i++)
           for(int j=0;j<m1;j++)
               for(int k=0;k<4;k++)
               {
                   int x = bu[k][0]+i;
                   int y = bu[k][1]+j;
                   if(x>=0&&x<n1&&y>=0&&y<m1&&mp[x][y]!='.'&&mp[i][j]!='.')
                   {
                       link2[mp[x][y]-'0'][mp[i][j]-'0'] = 1;
                       link2[mp[i][j]-'0'][mp[x][y]-'0'] = 1;
                   }
               }
       dfs1(0,-1);
       printf("Case #%d: ",i1);
       i1++;
       printf("%d\n",ans);
    }
    return 0;
}
//枚举方向写错dfs递归pre写错wa了好几发。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值