题意:
在R*C上有些艺术品..每个艺术品用非负数表示代表他附近那些格子需要保安...-1代表该格子上本来就是保安..必须保证艺术品关键的位置必须要有保安.或者不放这个艺术品..在这个艺术品上站保安..问最少要增加多少保安满足条件...
题解:
根据每件艺术品所需要的安保条件建边..注意..这个边的意思是两个点需要联系..所以艺术品指向保安和保安指向艺术品是一回事...题目就转化成了二分图的最小点覆盖问题(用最少的点覆盖所有的边..边是需要的安保关系..点是需要增加的保安数量)...等价于求其最大匹配...注意..建图有两种方式..一种是分奇偶点..建成两侧完全不同的点..答案就是跑最大匹配..第二种是两侧都是相同的点..边也是建双向边..答案是最大匹配/2
Program:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<stack>
#include<string.h>
#include<queue>
#define ll long long
#define esp 1e-5
#define MAXN 3005
#define MAXM 500005
#define oo 100000007
using namespace std;
struct node
{
int y,next;
}line[MAXM];
int match[MAXN],way[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 Lnum,_next[MAXN],arc[MAXN][MAXN];
bool used[MAXN];
void addline(int x,int y)
{
line[++Lnum].next=_next[x],_next[x]=Lnum,line[Lnum].y=y;
}
bool dfs(int x)
{
for (int k=_next[x];k;k=line[k].next)
{
int y=line[k].y;
if (used[y]) continue;
used[y]=true;
if (!match[y] || dfs(match[y]))
{
match[y]=x;
return true;
}
}
return false;
}
int getmax(int n)
{
int sum=0;
memset(match,0,sizeof(match));
for (int i=0;i<n;i++)
{
memset(used,false,sizeof(used));
sum+=dfs(i);
}
return sum;
}
int main()
{
int i,cases=0,R,C,x,y,h;
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
while (~scanf("%d%d",&R,&C) && R)
{
for (y=0;y<R;y++)
for (x=0;x<C;x++)
scanf("%d",&arc[y][x]);
Lnum=0,memset(_next,0,sizeof(_next));
for (y=0;y<R;y++)
for (x=0;x<C;x++)
if (arc[y][x]>0)
{
h=arc[y][x];
for (i=0;i<12;i++)
if (h&(1<<i))
{
int yy=y+way[i][0],xx=x+way[i][1];
if (xx<0 || yy<0 || xx>=C || yy>=R || arc[yy][xx]<0) continue;
addline(y*C+x,yy*C+xx),addline(yy*C+xx,y*C+x);
}
}
printf("%d. %d\n",++cases,getmax(R*C)/2);
}
return 0;
}
/*
3 4
0 0 512 0
536 512 0 0
0 0 512 0
3 4
0 0 0 0
512 536 0 0
0 0 0 0
0 0
3
1
*/