题目
http://acm.ecnu.edu.cn/problem/3346/
Description:
八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。
八皇后问题可以推广为更一般的 n 皇后摆放问题:这时棋盘的大小变为 n×n,而皇后个数也变成 n。
现在给你 n 个皇后的位置座标,问总共有多少对皇后互相冲突。
Iuput:
第一行一个整数 n,表示有 n 个皇后。
接下来 n 行,每行两个整数 x,y (1≤x,y≤n),中间用空格分开,表示 n 个皇后的坐标。
数据保证不会有两个皇后在同一个地方。
数据规模约定:
- 对于 60% 的数据,1≤n≤100。
- 对于 100% 的数据,1≤n≤10^5。
Output:
输出一个整数,表示有多少对皇后互相冲突。
Examples input:
3
1 1
1 2
1 3
Examples output:
3
思路
解法一:把每个点(皇后)的位置保存下来,然后两重循环判一下各个点是否存在冲突:X1 == X2 或 Y1 == Y2 或 |X1-X2| == |Y1-Y2|,累加存在冲突的点对,最后再输出。时间复杂度O(n^2)。这样只能过60%的数据,当输入数据过多时便会超时。
代码一
#include <bits/stdc++.h>
using namespace std;
#define N 100001
struct point
{
int x, y;
point(){}
point(int xx, int yy):x(xx), y(yy){}
};
vector<point> P;
int main()
{
int n;
cin >> n;
int x, y;
for(int i = 0; i < n; i++)
{
cin >> x >> y;
P.push_back(point(x, y));
}
int ans = 0;
for(int i = 0; i < P.size(); i++)
{
for(int j = i + 1; j < P.size(); j++)
{
if(P[i].x == P[j].x || P[i].y == P[j].y || (abs(P[i].x - P[j].x) == abs(P[i].y - P[j].y)))
ans++;
}
}
cout << ans <<endl;
return 0;
}
解法二:定义四个数组,分别保存同一行、列、副对角线、主对角线包含的皇后个数,然后一次遍历四个数组计算冲突的皇后,累加冲突总数,最后输出。时间复杂度O(n)。
代码二
#include <bits/stdc++.h>
using namespace std;
#define N 100010
typedef long long ll;
ll row[N];//行
ll col[N];//列
ll dia1[2*N];//副对角线 y = -x + b
ll dia2[2*N];//主对角线 y = x + b
int main()
{
int n;
cin >> n;
if(n == 1)
cout << 0 << endl;
else
{
int x, y;
for(int i = 0; i < n; i++)
{
cin >> x >> y;
row[x]++;
col[y]++;
dia1[x+y]++;
dia2[y-x+N]++;//+N用于偏移 防止数组下标为负
}
ll ans = 0;
for(int i = 0; i < N; i++)
{
if(row[i] >= 2)
ans += row[i] * (row[i] - 1) / 2;//计算每行冲突数
if(col[i] >= 2)
ans += col[i] * (col[i] - 1) / 2;//计算每列冲突数
}
for(int i = 1; i < 2*N; i++)
{
if(dia1[i] >= 2)
ans += dia1[i] * (dia1[i] - 1) / 2;//计算每副对角线冲突数
if(dia2[i] >= 2)
ans += dia2[i] * (dia2[i] - 1) / 2;//计算每主对角线冲突数
}
cout << ans << endl;
}
return 0;
}