题目叫国家宝藏?!23333...
很棒的行列匹配。给出一张图,mat[i][j] != 0表示这是一个价值为mat[i][j]的宝物,每个宝物需要一些人看守,最多为12人,即
分析:建图的话,就是分成行列编号,然后对于每一对位置矛盾的建边(单向),求最大匹配即可。
P:再次声明了,行列匹配的话需要编号这一玩意儿~
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
#define N 55
#define M 2505
vector<int> v[M];
int mat[N][N];
int a[N][N];
int link[M], vis[M];
int r, c;
int n, m;
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};
void init()
{
for ( int i = 1; i <= n; i++ )
{
v[i].clear();
}
memset(a, 0, sizeof(a));
m = n = 1;
}
bool ok( int x, int y )
{
return (x <= r && x >= 1 && y <= c && y >= 1);
}
void build( int val, int x, int y, int f)
{
for( int i = 0; i < 12; i++ )
{
if( (val >> i) & 1 )
{
int xx = dir[i][0] + x;
int yy = dir[i][1] + y;
if( ok(xx, yy) && a[xx][yy] )
{
int u = a[x][y];
int to = a[xx][yy];
if( f )
{
v[u].push_back(to);
}
else
{
v[to].push_back(u);
}
}
}
}
}
int dfs( int u )
{
for ( int i = 0; i < v[u].size(); i++)
{
int to = v[u][i];
if( !vis[to] )
{
vis[to] = 1;
if( link[to] == -1 || dfs( link[to] ) )
{
link[to] = u;
return 1;
}
}
}
return 0;
}
int main()
{
int tt = 1;
while(~scanf("%d %d", &r, &c) && (r || c))
{
init();
for ( int i = 1; i <= r; i++ )
{
for( int j = 1; j <= c; j++ )
{
scanf("%d", &mat[i][j]);
if( mat[i][j] != -1 )
{
if ( (i + j) % 2 )
a[i][j] = n++;
else
a[i][j] = m++;
}
}
}
for( int i = 1; i <= r; i++ )
{
for( int j = 1; j <= c; j++ )
{
if( a[i][j] )
{
build(mat[i][j], i, j, (i+j)%2);
}
}
}
memset(link, -1, sizeof(link));
int ans = 0;
for ( int i = 1; i < n; i++ )
{
memset(vis, 0, sizeof(vis));
ans += dfs(i);
}
printf("%d. %d\n", tt++, ans);
}
return 0;
}