1 3 512 -1 2048 2 3 512 2560 2048 512 2560 2048 0 0
1. 0 2. 2HintThe picture below shows the solution of the second test case where the two artifacts in the middle are replaced by guards.
黑白染色(即奇偶数)+最小点覆盖
/*------------------黑白染色+最小点覆盖---------------------
HDU 3360 National Treasures 奇偶染色+最小点覆盖 ACM Steps 6.3.8
-----------------------------*/
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 51;
int vis[maxn*maxn];
int father[maxn*maxn];
vector <int> graph[maxn*maxn];//define graph
int n, m;
int map[maxn][maxn];
//define the guard status
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 };
bool dfs(int head){
int i,now;
int size = graph[head].size();
for (i = 0; i < size; i++){
now = graph[head][i]; //获得head位置中的某适合的guard
if (!vis[now]){ //
vis[now] = true;
if (father[now] == -1 || dfs(father[now])){ //寻找增广路径是否行
father[now] = head;
return true;
}
}
}
return false;
}
int find(){
int ans = 0, i = 0, j = 0;
memset(father, -1, sizeof(father));
for (; i < n; i++){
for (j = 0; j < m; j++){
if ((i + j) % 2){ //奇偶分组
memset(vis, 0, sizeof(vis));
if (dfs(m*i + j))
ans++;
}
}
}
return ans;
}
int main()
{
int cas = 1,i,j;
while (scanf("%d %d", &n, &m) != EOF && n&& m){
for ( i = 0; i < n; i++)
for (j = 0; j < m; j++)
scanf("%d", &map[i][j]);
for (i = 0; i < n*m; i++)
graph[i].clear();
for (i = 0; i < n; i++)
{
for ( j = 0; j < m; j++)
{
int x = map[i][j];
if (x == -1)
continue;
for (int k = 0; k < 12; k++, x >>= 1)
{
if (!x)//如果x==0就跳出
break;
if (!(x & 1))//判断能否站守卫 5&1==true,4&1==false
continue;
int xx = i + dir[k][0];
int yy = j + dir[k][1];
if (xx < 0 || xx >= n || yy < 0 || yy >= m)
continue;
if (map[xx][yy] == -1)
continue;
if ((i + j) % 2)
graph[i*m + j].push_back(xx*m + yy);
else
graph[xx*m + yy].push_back(i*m + j);
}
}
}
printf("%d. %d\n", cas++, find());
}
return 0;
}
|