hdu3360

/*大致上题意就是每个宝物最多有12个点需要侍卫守护,仔细一看如果宝物地点为i,j,需要保护的点是x,y的话,那么(i+j)%2!=(x+y)%2,那么就可以按照棋盘奇偶划分,然后求一个最小点覆盖即可。*/
#include <algorithm>
#include <bitset>
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <iostream>
#include <iterator>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;

int r,c,g[60][60],x[60][60],ans,re[1600],vi[1600],n,m;
int dic[12][2]={-1,-2,-2,-1,-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,0,0,1,1,0,0,-1};
vector<int>vt[1501];

int inside(int x,int y)
{
    return x>=1&&x<=r&&y>=1&&y<=c;
}

void gao(int i,int j,int v,int flag)
{
    for(int k=0;k<12;k++)
    {
            if((v>>k)&1)
            {
                        int tx=i+dic[k][0];
                        int ty=j+dic[k][1];
                        if(inside(tx,ty)&&g[tx][ty]!=-1)
                        {
                                                        if(flag)
                                                        vt[x[i][j]].push_back(x[tx][ty]);
                                                        else
                                                        vt[x[tx][ty]].push_back(x[i][j]);
                        }
            }
    }
}

int dfs(int y)
{
    for(int i=0;i<vt[y].size();i++)
    {
            int j=vt[y][i];
            if(!vi[j])
            {
                      vi[j]=1;
                      if(re[j]==0||dfs(re[j]))
                      {
                                            re[j]=y;
                                            return 1;
                      } 
            }
    }
    return 0;
}
void match()
{
     ans=0;
     memset(re,0,sizeof(re));
     for(int i=1;i<=n;i++)
     {
             memset(vi,0,sizeof(vi));
             ans+=dfs(i);
     }
     return;
}

int main()
{
    int pro=0;
    while(scanf("%d%d",&r,&c),r||c)
    {
                                   n=0,m=0;
                                   for(int i=1;i<=1500;i++)
                                   vt[i].clear();
                                   for(int i=1;i<=r;i++)
                                   for(int j=1;j<=c;j++)
                                   {
                                           scanf("%d",&g[i][j]);
                                           if(g[i][j]!=-1)
                                           {
                                                          if((i+j)%2)
                                                          x[i][j]=++n;
                                                          else
                                                          x[i][j]=++m;
                                           }
                                   }
                                   for(int i=1;i<=r;i++)
                                   for(int j=1;j<=c;j++)
                                   {
                                           if(g[i][j]!=-1)
                                           gao(i,j,g[i][j],(i+j)%2);
                                   } 
                                   match();
                                   printf("%d. %d\n",++pro,ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值