http://livearchive.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=32&page=show_problem&problem=2923
一开始是想了暴力,即对于每个皇后找到与之冲突的所有皇后,显然,O(n^2)果断是TLE的(皇后的总数不会超过n),然后就要想办法优化,想了排序,想了对于每个点当找到超过8个冲突时可停止查找(因为每个皇后最多与其他8个产生冲突)。。反正就是想了挺久的,走上了这条不归路。。。。
最后的做法,不是我想出来的,是一个与我一开始的想法完全不同的思考方向,不是找每个皇后的所有冲突,而是找所有可能发生冲突的地方有多少个皇后,即计算每一行每一列每条对角线上一共有多少个皇后,如果有k个皇后,就会有k-1对冲突(因为冲突的皇后之间必须无障碍)。这种做法,O(n),而且也不用保存每个皇后的位置,代码也很短。
反思:为什么我总是把问题复杂化。。。。。
代码:
row[x] 表示第x行有几个皇后
col[y] 表示第y列有几个皇后
dia1[x-y] 表示主对角线(把负数部分移到正数部分的后面)
一开始是想了暴力,即对于每个皇后找到与之冲突的所有皇后,显然,O(n^2)果断是TLE的(皇后的总数不会超过n),然后就要想办法优化,想了排序,想了对于每个点当找到超过8个冲突时可停止查找(因为每个皇后最多与其他8个产生冲突)。。反正就是想了挺久的,走上了这条不归路。。。。
最后的做法,不是我想出来的,是一个与我一开始的想法完全不同的思考方向,不是找每个皇后的所有冲突,而是找所有可能发生冲突的地方有多少个皇后,即计算每一行每一列每条对角线上一共有多少个皇后,如果有k个皇后,就会有k-1对冲突(因为冲突的皇后之间必须无障碍)。这种做法,O(n),而且也不用保存每个皇后的位置,代码也很短。
反思:为什么我总是把问题复杂化。。。。。
代码:
row[x] 表示第x行有几个皇后
col[y] 表示第y列有几个皇后
dia1[x-y] 表示主对角线(把负数部分移到正数部分的后面)
dia2[x+y] 表示副对角线
代码:
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 30000 * 2 + 10;
int row[N/2], col[N/2], dia1[N], dia2[N];
int main()
{
//freopen("a", "r", stdin);
//freopen("b", "w", stdout);
int n, g;
while (scanf("%d", &n) != EOF && n)
{
memset(row, 0, sizeof(row));
memset(col, 0, sizeof(col));
memset(dia1, 0, sizeof(dia1));
memset(dia2, 0, sizeof(dia2));
scanf("%d", &g);
int k, x, y, s, t, tmpx, tmpy;
while (g--)
{
scanf("%d%d%d%d%d", &k, &x, &y, &s, &t);
for (int i = 0; i < k; i++)
{
tmpx = x + i * s;
tmpy = y + i * t;
row[tmpx]++;
col[tmpy]++;
int tmp = tmpx - tmpy;
if(tmp < 0) tmp += 2 * (n-1) + 1;
dia1[tmp]++;
dia2[tmpx+tmpy]++;
}
}
int sum = 0;
for (int i = 1; i <= n; i++)
{
if (row[i]) sum += row[i] - 1;
if (col[i]) sum += col[i] - 1;
}
for (int i = 0; i <= n + n; i++)
{
if (dia1[i]) sum += dia1[i] - 1;
if (dia2[i]) sum += dia2[i] - 1;
}
printf("%d\n", sum);
}
}