这道题向了我好久,看了题解也是一时没想通。
二分图的建模个人感觉挺不容易的,可能是刚学的原因吧~
题意:大厅每个位置都有一个文物或者一个守卫,
文物是安全的前提是: 关键位置上必须有一个守卫,或者文物本身的位置上有一个守卫。
求保证每个文物是安全的守卫的最少数量。
分析:由于文物的关键位置在文物的马步或者相邻的位置上,所以此问题可看成二分图。
以(0,0)位置出发,格子可以分成与(0,0)点距离为奇数的点和偶数的点。
之后求二分图的最大匹配即可。
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int>map[2550];//建邻接表
int r,c,value[55][55],pre[2550];
int dir[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}};
int rev[12]={4,5,6,7,0,1,2,3,10,11,8,9};
int judge[12]=
{
0x001,0x002,0x004,0x008,
0x010,0x020,0x040,0x080,
0x100,0x200,0x400,0x800
};
bool flag[2550];
int find(int cur)
{
int i,j;
for(i=0;i<map[cur].size();i++)
{
int k=map[cur][i];
if(!flag[k])
{
flag[k]=1;
if(!pre[k]||find(pre[k]))
{
pre[k]=cur;
return 1;
}
}
}
return 0;
}
void make_map()
{
int i,j,k;
for(i=0;i<r*c;i++)map[i].clear();
for(i=0;i<r;i++)
for(j=0;j<c;j++)
{
int s=i*c+j;
if((i+j)%2==0)continue;
if(value[i][j]==-1)continue;
for(k=0;k<12;k++)
{
int x=i+dir[k][0];
int y=j+dir[k][1];
int ss=x*c+y;
if(x<0||x>=r||y<0||y>=c)continue;
if(value[x][y]==-1)continue;
if(judge[k]&value[i][j])
map[s].push_back(ss);
else if(judge[rev[k]]&value[x][y])
map[s].push_back(ss);
}
}
}
int main()
{
int i,j,k=1,a,b;
while(scanf("%d%d",&r,&c)!=-1&&(r+c))
{
memset(pre,0,sizeof(pre));
int ans=0;
for(i=0;i<r;i++)
for(j=0;j<c;j++)
make_map();
int sum=0,s;
for(i=0;i<r;i++)
for(j=0;j<c;j++)
{
if(value[i][j]!=-1&&((i+j)&1))//距离为奇数且没有守卫的点进行匹配
{
memset(flag,0,sizeof(flag));
s=i*c+j;
sum+=find(s);
}
}
printf("%d. %d\n",k++,sum);
}
return 0;
}