#include #include #include #include using namespace std; struct Cell { Cell(int a, int b, int p, int at, double c) : x(a), y(b), points(p), attacked(at), coef(c) {}; int x; int y; int points; double coef; int attacked; bool operator< (const Cell& other) const { if (x == other.x && y == other.y) { return attacked > other.attacked; } return coef < other.coef; } }; int N, R, K; int board[200][200]; ofstream fout("queens.out"); ifstream fin("queens.in"); int points[200][200]; bool visited[200][200]; priority_queue cells, cells2; int horSum[200][200] = { 0 }, vertSum[200][200], lDiagSum[200][200], rDiagSum[200][200]; int horCount[200][200][51], vertCount[200][200][51], lDiagCount[200][200][51], rDiagCount[200][200][51]; int countEqual[200][200]; int total = 0, queensLeft = N * N; double average = 0; queue > morePoints; queue > moreQueens; int calculatePointsIn(int x, int y) { int hsum, vsum, rsum, lsum, bigger, smaller, maxCount = 0; int hcount = 0, vcount = 0, rcount = 0, lcount = 0, smallCount[51], bigCount[51], count[51]; memset(count, 0, 4 * 51); //horizontal if (y - R - 1 < 0) { memset(smallCount, 0, 4 * 51); smaller = 0; } else { smaller = horSum[x][y - R - 1]; memcpy(smallCount, horCount[x][y - R - 1], 4 * 51); } if (y + R >= N) { bigger = horSum[x][N - 1]; memcpy(bigCount, horCount[x][N - 1], 4 * 51); } else { bigger = horSum[x][y + R]; memcpy(bigCount, horCount[x][y + R], 4 * 51); } hsum = bigger - smaller; for (int i = 1; i <= 50; i++) { count[i] += bigCount[i] - smallCount[i]; } //vertical if (x - R - 1 < 0) { smaller = 0; memset(smallCount, 0, 4 * 51); } else { smaller = vertSum[x - R - 1][y]; memcpy(smallCount, vertCount[x - R - 1][y], 4 * 51); } if (x + R >= N) { bigger = vertSum[N - 1][y]; memcpy(bigCount, vertCount[N - 1][y], 4 * 51); } else { bigger = vertSum[x + R][y]; memcpy(bigCount, vertCount[x + R][y], 4 * 51); } vsum = bigger - smaller; for (int i = 1; i <= 50; i++) { count[i] += bigCount[i] - smallCount[i]; } //left diagonal if (x - R - 1 < 0 || y - R - 1 < 0) { smaller = 0; memset(smallCount, 0, 4 * 51); } else { smaller = lDiagSum[x - R - 1][y - R - 1]; memcpy(smallCount, lDiagCount[x - R - 1][y - R - 1], 4 * 51); } if (x + R >= N || y + R >= N) { if (x >= y) { bigger = lDiagSum[N - 1][N - 1 - (x - y)]; memcpy(bigCount, lDiagCount[N - 1][N - 1 - (x - y)], 4 * 51); } else { bigger = lDiagSum[N - 1 - (y - x)][N - 1]; memcpy(bigCount, lDiagCount[N - 1 - (y - x)][N - 1], 4 * 51); } } else { bigger = lDiagSum[x + R][y + R]; memcpy(bigCount, lDiagCount[x + R][y + R], 4 * 51); } lsum = bigger - smaller; for (int i = 1; i <= 50; i++) { count[i] += bigCount[i] - smallCount[i]; } // right diagonal if (x - R - 1 < 0 || y + R + 1 < 0) { smaller = 0; memset(smallCount, 0, 4 * 51); } else { smaller = rDiagSum[x - R - 1][y + R + 1]; memcpy(smallCount, rDiagCount[x - R - 1][y + R + 1], 4 * 51); } if (x + R >= N || y - R < 0) { if (x + y > N - 1) { bigger = rDiagSum[N - 1][x + y - N + 1]; memcpy(bigCount, rDiagCount[N - 1][x + y - N + 1], 4 * 51); } else { bigger = rDiagSum[x + y][0]; memcpy(bigCount, rDiagCount[x + y][0], 4 * 51); } } else { bigger = rDiagSum[x + R][y - R]; memcpy(bigCount, rDiagCount[x + R][y - R], 4 * 51); } rsum = bigger - smaller; for (int i = 1; i <= 50; i++) { count[i] += bigCount[i] - smallCount[i]; if (maxCount < count[i]) maxCount = count[i]; } int sum = hsum + vsum + lsum + rsum; countEqual[x][y] = maxCount; return sum * maxCount; } int calculateverticalIn(int x, int y) { if (x == 0) { vertCount[x][y][board[x][y]]++; return board[x][y]; } memcpy(vertCount[x][y], vertCount[x - 1][y], 4 * 51); vertCount[x][y][board[x][y]]++; return board[x][y] + vertSum[x - 1][y]; } void calculateverticals() { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) vertSum[i][j] = calculateverticalIn(i, j); } int calculatehorizontalIn(int x, int y) { horCount[x][y][board[x][y]]++; if (y == 0) return board[x][y]; memcpy(horCount[x][y], horCount[x][y - 1], 4 * 51); horCount[x][y][board[x][y]]++; return board[x][y] + horSum[x][y - 1]; } void calculatePoints() { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) { int p = calculatePointsIn(i, j); cells.push(Cell(i, j, p, 0, p)); points[i][j] = p; total += p; } average = (double)total / (N * N); cells2 = cells; } void calculatehorizontals() { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) horSum[i][j] = calculatehorizontalIn(i, j); } int calculateLeftDiagonalIn(int x, int y) { lDiagCount[x][y][board[x][y]]++; if (x == 0 || y == 0) return board[x][y]; memcpy(lDiagCount[x][y], lDiagCount[x - 1][y - 1], 4 * 51); lDiagCount[x][y][board[x][y]]++; return board[x][y] + lDiagSum[x - 1][y - 1]; } void calculateLeftDiagonals() { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) lDiagSum[i][j] = calculateLeftDiagonalIn(i, j); } int calculateRightDiagonalIn(int x, int y) { rDiagCount[x][y][board[x][y]]++; if (x == 0 || y == N - 1) return board[x][y]; memcpy(rDiagCount[x][y], rDiagCount[x - 1][y + 1], 4 * 51); rDiagCount[x][y][board[x][y]]++; return board[x][y] + rDiagSum[x - 1][y + 1]; } void calculateRightDiagonals() { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) rDiagSum[i][j] = calculateRightDiagonalIn(i, j); } ///helper void print(int arr[][200]) { cout << endl; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) cout << arr[i][j] << " "; cout << endl; } } int greedyTacticMoreQueens() { int attacked[200][200]; memset(attacked, 0, 200 * 200); int left = K; queensLeft = N*N; int totalPoints = 0; while (!cells.empty()) { Cell best = cells.top(); cells.pop(); //Cell best = first; int x = best.x, y = best.y; if (attacked[x][y] > left || attacked[x][y] != best.attacked || visited[x][y]) { if (attacked[x][y] > left && attacked[x][y] == best.attacked && !visited[x][y]) { queensLeft--; total -= best.points; average = (double)(total) / queensLeft; } continue; } moreQueens.push(pair(best.x + 1, best.y + 1)); //fout << best.x + 1 << " " << best.y + 1 << endl; visited[x][y] = 1; queensLeft--; total -= best.points; if (queensLeft != N * N) average = (double)(total) / queensLeft; totalPoints += best.points; left -= attacked[x][y]; for (int i = -R; i <= R; i++) { if (x + i >= 0 && x + i < N) { attacked[x + i][y]++; double coef = (double)points[x + i][y] - (attacked[x + i][y] - left/queensLeft) * average; cells.push(Cell(x + i, y, points[x + i][y], attacked[x + i][y], coef)); } if (y + i >= 0 && y + i < N) { attacked[x][y + i]++; double coef = (double)points[x][y + i] - (attacked[x][y + i] - left / queensLeft) * average; cells.push(Cell(x, y + i, points[x][y + i], attacked[x][y + i], coef)); } if (x + i >= 0 && x + i < N && y + i >= 0 && y + i < N) { attacked[x + i][y + i]++; double coef = (double)points[x + i][y + i] - (attacked[x + i][y + i] - left / queensLeft) * average; cells.push(Cell(x + i, y + i, points[x + i][y + i], attacked[x + i][y + i], coef)); } if (x + i >= 0 && x + i < N && y - i >= 0 && y - i < N) { attacked[x + i][y - i]++; double coef = (double)points[x + i][y - i] - (attacked[x + i][y - i] - left / queensLeft) * average; cells.push(Cell(x + i, y - i, points[x + i][y - i], attacked[x + i][y - i], coef)); } } attacked[x][y] -= 3; } return totalPoints; } int greedyTacticMorePoints() { int attacked[200][200]; memset(attacked, 0, 200 * 200); int left = K; int totalPoints = 0; while (!cells2.empty()) { Cell first = cells2.top(); cells2.pop(); Cell best = first; int x = first.x, y = first.y; if (attacked[x][y] > left) { continue; } if (attacked[x][y] > 1) { Cell second = cells2.top(); cells2.pop(); if (first.points*attacked[second.x][second.y] <= attacked[x][y] * second.points) { best = second; x = best.x; y = best.y; } } morePoints.push(pair(best.x + 1, best.y + 1)); //fout << best.x + 1 << " " << best.y + 1 << endl; totalPoints += best.points; left -= attacked[x][y]; for (int i = -R; i <= R; i++) { if (x + i >= 0 && x + i < N) attacked[x + i][y]++; if (y + i >= 0 && y + i < N) attacked[x][y + i]++; if (x + i >= 0 && x + i < N && y + i >= 0 && y + i < N) attacked[x + i][y + i]++; if (x + i >= 0 && x + i < N && y - i >= 0 && y - i < N) attacked[x + i][y - i]++; } attacked[x][y] -= 3; } return totalPoints; } int main() { fin >> N >> R >> K; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) fin >> board[i][j]; calculatehorizontals(); calculateverticals(); calculateLeftDiagonals(); calculateRightDiagonals(); calculatePoints(); double average = total / N * N; int max = cells.top().points; int mq = greedyTacticMoreQueens(); int mp = greedyTacticMorePoints(); if (mq > mp) { while (!moreQueens.empty()) { pair top = moreQueens.front(); moreQueens.pop(); fout << top.first << " " << top.second << endl; } } else { while (!morePoints.empty()) { pair top = morePoints.front(); morePoints.pop(); fout << top.first << " " << top.second << endl; } } //cout << "MQ: " << mq << " MP: " << mp << endl; return 0;