题目描述
小 Z 最近捡到了一个棋盘,他想在棋盘上摆放 K 个皇后。他想知道在他摆完这 K 个皇后之后,棋盘上还有多少个格子是不会被攻击到的。
注意:一个皇后会攻击到这个皇后所在的那一行,那一列,以及两条对角线。
输入格式
第一行三个正整数 n,m,K,表示棋盘的行列,以及小 Z 摆放的皇后的个数。
接下来 K 行,每行两个正整数 x,y,表示这个皇后被摆在了第 x行,第 y 列,数据保证任何两个皇后都不会被摆在同一个格子里。
输出格式
仅一个整数,表示棋盘上还有多少个格子是不会被攻击到的。
输入输出样例
输入 #1
12 13 6 10 4 12 10 1 1 2 3 3 2 2 6
输出 #1
25
分析:
由于数据范围较大,暴力会超时;
正确做法:
记录下输入的每个皇后之后,从每一行开始遍历;如果该行有皇后,直接跳出;
如果该行没有皇后,设该行行数为i,初始时该行不被攻击的格子数为m;
遍历每一个K皇后;判断其列和两条对角线是否影响该行某个位置;
如果某个K皇后影响了第i行某列,就用c[]数组标记该位置,并且该行不被攻击的格子数-1;
(好像分析的有点绕口,不懂的可以再看看注释)
注:数组c用来标记某个位置是否已有K皇后攻击过,由于被K皇后攻击过后,该行不被攻击的格子数-1,故用数组c标记防止重复相减。
AC代码(含注释):
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> PII;
int n, m;
int k;
int x[510], y[510];
int c[20010];//用来标记该位置是否被攻击的数组
int ans = 0;//棋盘上不会被攻击到的格子数
int main()
{
cin >> n >> m >> k;
for (int i = 1; i <= k; i++) cin >> x[i] >> y[i];
//从每行开始遍历
for (int i = 1; i <= n; i++) {
int num = m;//初始时每行格子数为m
for (int j = 1; j <= k; j++) {//遍历每个K皇后
if (x[j] == i) {//若该行有K皇后,直接跳出;
num = 0;
break;
}
else {//如果该行没有皇后,判断其他K皇后的列和两条对角线是否影响该行某个位置;
if (c[y[j]] != i) {//判断列;初始时c[y[j]] != i;一旦该列有K皇后,就标记该位置
c[y[j]] = i;
num--;
}
if (x[j] + y[j] - i >= 1 && x[j] + y[j] - i <= m && c[x[j] + y[j] - i] != i) {//判断左下—右上对角线
num--;
c[x[j] + y[j] - i] = i;
}
if (y[j] + (i - x[j]) >= 1 && y[j] + (i - x[j]) <= m && c[y[j] + (i - x[j])] != i) {//判断左上-右下对角线
num--;
c[y[j] + (i - x[j])] = i;
}
}
}
ans += num;//每行扫描结束后加上该行不会被攻击到的格子数
}
cout << ans;
return 0;
}