1.​​题目链接​​。题目大意:John有一块农田,现在他需要在农田k个空闲的位置放置驱逐bird的scarecrows。已知每个scarecrows各异保护的范围是距离它哈密顿距离不超过k的地方,现在给你这k个点的坐标,求出最少需要放置多少个scarecrows才能保护好整片农田。

2.由于k很小,不超过10.所以我们可以直接枚举所有的组合。网上很多题解都是说枚举,但是很少有说明为什么是可以这样枚举的,所以对于很多刚刚学习这一知识的人不是很友好,看了半天的代码也是一头雾水,现在我简单的说一下自己的看法。我们知道,k个scarecrows一共有pow(2,k)个状态,这个很好理解,因为每一个scarecrows都是有两种状态,选或者不选。所以我们把考虑一个二进制维k位的整数,其中每一位对应的就是这个编号为i的scarecrows的状态。举个例子:比如12=1100.假设我们有四个scarecrows,那么12代表的就是第1,2个不选,第3,4个选。这也就是状态的压缩,那么我们知道从0到pow(2,k-1)这些数据的二进制位就代表了所有的情况,所以我们从0枚举到pow(2,k)-1.对于每一个数字,把他们为1的所有位数取出来,这样我们就知道到底选了哪几个,然后检查答案即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int r[51], c[51];
int f[51];
int n;
int m;
int vis[51][51];
int a[10];
const int INF = 1e9 + 10;
#pragma warning(disable:4996)
int main()
{
while (~scanf("%d", &n) && n)
{

scanf("%d", &m);
for (int i = 0; i < m; i++)
scanf("%d%d", &r[i], &c[i]);
for (int i = 0; i < m; i++)
scanf("%d", &f[i]);
int ans = (1 << m);
int res = INF;
for (int i = 0; i < ans; i++)
{
int num = 0;
memset(vis, 0, sizeof(vis));
//这里说明一下:这是在取出i的二进制所以为1的位置
for (int j = 0; j < m; j++)
if (i&(1 << j))
a[num++] = j;
int flag = 1;
for (int ii = 1; ii <= n; ii++)
{
for (int jj = 1; jj <= n; jj++)
{
for (int kk = 0; kk < m; kk++)
if (r[kk] == ii && c[kk] == jj)
vis[ii][jj] = 1;
if (vis[ii][jj])
continue;
for (int kk = 0; kk < num; kk++)
{
if (abs(ii - r[a[kk]]) + abs(jj - c[a[kk]]) <= f[a[kk]])
{
vis[ii][jj] = 1;
break;
}
}
if (vis[ii][jj] == 0)
flag = 0;
if (!flag)
break;
}
if (!flag)
break;
}
if (flag)
res = min(res, num);
}
if (res == INF)
puts("-1");
else
printf("%d\n", res);
}
return 0;
}