Problem J
Place the Guards
Input: Standard Input
Output: Standard Output
The king of Amazing Land has a secret place where he keeps
his treasure. No one knows what is the size of that place. Some say that it is (4
* 4) and some others say that it is (1000 * 1000). The rooms in this
secret place are also square shaped and of unit length and width. So a (4 * 4) place has 16
rooms as shown in the pictures below. So a (n * n) place has n^2
or (n * n) rooms. n guards are used to look after the (n * n)
sized secret place. In the picture below each second largest square denotes a
room. The gray square inside each room indicates free space where the guards
stand. The outgoing tunnels (dark gray in color) from the free space denote the
tunnels to go into and out of the rooms. As you can see that the tunnels are
designed in such a way that only the guards on the same row, same column and
same diagonal can see each other. If we use (row, column) denoting scheme we
can say that in figure 1 guard (2, 1) can see guard (3, 2) and
guard (3,2) can see guard (4, 3). Although guard (2,1) and
guard (4, 3) are in the same diagonal they cannot see each other as
guard (3, 2) stands between them. For obvious reasons guard (2, 1)
can see guard (2, 4) but guard (3, 2) cannot see guard (2, 4).
The King always places his guards in such a way that no guard can see any other
guard. In the empty rooms (where there is no guard) he keeps his treasure. The
King arranges his guards in this way because he thinks when a guard sees
another guard they start gossiping and thus lose concentration. You are to help
the King to place his guards.
|
|
Fig 1:
Invalid Guard Layout Fig 2: Valid Guard
Layout
Input
Input
File will contain an integer in each line, which indicates the value of n (The
length or width of one side of the secret place). Remember that (1<n<1001). Input
is terminated by End of File.
Output
As it is obvious that only one guard can be placed in
each column. For each input value of n you will have to print a line of n
integers. The integers will be separated by a single space. These
integers denote the row positions of guards in each column. For the valid
configuration of guards in figure 2 you will print the line 2 4 1 3 as
in column 1 the guard is placed on row 2, in column 2 the guard is placed on
row 4 and so on. There can be multiple solutions. Any good solution will be
accepted. If guards cannot be placed in the secret place print the line
“Impossible” in a single line.
Sample Input
4
8
10
Sample Output
2 4 1 3
4 6 8 2 7 1 3 5
2 4 6 8 10 1 3 5 7 9
__________________________________________________________________________________________
Shahriar Manzoor
數學解如下,轉自網路
一、当n mod 6 != 2 且 n mod 6 != 3时,有一个解为:
2,4,6,8,...,n,1,3,5,7,...,n-1 (n为偶数)
2,4,6,8,...,n-1,1,3,5,7,...,n (n为奇数)
(上面序列第i个数为ai,表示在第i行ai列放一个皇后;... 省略的序列中,相邻两数以2递增。下同)
二、当n mod 6 == 2 或 n mod 6 == 3时,
(当n为偶数,k=n/2;当n为奇数,k=(n-1)/2)
k,k+2,k+4,...,n,2,4,...,k-2,k+3,k+5,...,n-1,1,3,5,...,k+1 (k为偶数,n为偶数)
k,k+2,k+4,...,n-1,2,4,...,k-2,k+3,k+5,...,n-2,1,3,5,...,k+1,n (k为偶数,n为奇数)
k,k+2,k+4,...,n-1,1,3,5,...,k-2,k+3,...,n,2,4,...,k+1 (k为奇数,n为偶数)
k,k+2,k+4,...,n-2,1,3,5,...,k-2,k+3,...,n-1,2,4,...,k+1,n (k为奇数,n为奇数)
#include <stdio.h>
int main() {
int n, k, i;
while(scanf("%d", &n) == 1) {
if(n <= 3) {
puts("Impossible");
continue;
}
if(n%6 != 2 && n%6 != 3) {
printf("2");
for(i = 4; i <= n; i += 2)
printf(" %d", i);
for(i = 1; i <= n; i += 2)
printf(" %d", i);
} else {
if(n&1) k = (n-1)/2;
else k = n/2;
if(k%2 == 0 && n%2 == 0) {
printf("%d", k);
for(i = k+2; i <= n; i += 2)
printf(" %d", i);
for(i = 2; i <= k-2; i += 2)
printf(" %d", i);
for(i = k+3; i <= n-1; i += 2)
printf(" %d", i);
for(i = 1; i <= k+1; i += 2)
printf(" %d", i);
}
if(k%2 == 0 && n%2 == 1) {
printf("%d", k);
for(i = k+2; i <= n-1; i += 2)
printf(" %d", i);
for(i = 2; i <= k-2; i += 2)
printf(" %d", i);
for(i = k+3; i <= n-2; i += 2)
printf(" %d", i);
for(i = 1; i <= k+1; i += 2)
printf(" %d", i);
printf(" %d", n);
}
if(k%2 == 1 && n%2 == 0) {
printf("%d", k);
for(i = k+2; i <= n-1; i += 2)
printf(" %d", i);
for(i = 1; i <= k-2; i += 2)
printf(" %d", i);
for(i = k+3; i <= n; i += 2)
printf(" %d", i);
for(i = 2; i <= k+1; i += 2)
printf(" %d", i);
}
if(k%2 == 1 && n%2 == 1) {
printf("%d", k);
for(i = k+2; i <= n-2; i += 2)
printf(" %d", i);
for(i = 1; i <= k-2; i += 2)
printf(" %d", i);
for(i = k+3; i <= n-1; i += 2)
printf(" %d", i);
for(i = 2; i <= k+1; i += 2)
printf(" %d", i);
printf(" %d", n);
}
}
puts("");
}
return 0;
}
隨機化方法:但是不會調好的隨機
原本想打表的,上傳卻發現 Code length can't be over 40 kilobytes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
int P[1005], n;
void step1() {
int i, j, k;
for(i = 1; i <= n; i++)
P[i] = i;
for(i = 1; i <= 65536; i++) {
j = rand()%n+1;
k = rand()%n+1;
swap(P[j], P[k]);
}
}// random init solution for n-queen
int column[1005];
int markRight[2005], markLeft[2005];
int error;
int injure[2005], inSize, chNode, chColumn;
int mnAttack[2005], mnSize;
int mn;
void step2a() {
int i, x, y, right, left;
inSize = 0;
for(i = 1; i <= n; i++) {
x = i, y = P[i];
if(x >= y) right = x-y;
else right = y-x+n;
x = i, y = n-P[i]+1;
if(x >= y) left = x-y;
else left = y-x+n;
if(column[P[i]] > 1 || markRight[right] > 1 || markLeft[left] > 1) {
injure[inSize++] = i;
}
}
if(inSize == 0) {
printf("%d XXX\n", error);
}
chNode = injure[rand()%inSize];
//printf("injure %d\n", inSize);
x = chNode, y = P[chNode];
if(x >= y) right = x-y;
else right = y-x+n;
x = chNode, y = n-P[chNode]+1;
if(x >= y) left = x-y;
else left = y-x+n;
if(column[P[chNode]] == 2) error--;
if(markRight[right] == 2) error--;
if(markLeft[left] == 2) error--;
column[P[chNode]]--, markRight[right]--, markLeft[left]--;
mn = column[P[chNode]]+markRight[right]+markLeft[left];
}
void step2b() {
int i, x, y, right, left, tmp;
mnSize = 0;
for(i = 1; i <= n; i++) {
x = chNode, y = i;
if(x >= y) right = x-y;
else right = y-x+n;
x = chNode, y = n-i+1;
if(x >= y) left = x-y;
else left = y-x+n;
tmp = column[i] + markRight[right] + markLeft[left];
//printf("i %d : %d %d queen\n", i, tmp, mn);
if(tmp <= mn)
mnAttack[mnSize++] = i;
}
/*printf("set :");
for(i = 0; i < mnSize; i++)
printf(" %d", mnAttack[i]);
puts("");*/
if(mnSize == 0) {
for(i = 1; i <= n; i++) {
x = chNode, y = i;
if(x >= y) right = x-y;
else right = y-x+n;
x = chNode, y = n-i+1;
if(x >= y) left = x-y;
else left = y-x+n;
tmp = column[i] + markRight[right] + markLeft[left];
//printf("i %d : %d %d queen\n", i, tmp, mn);
if(tmp == mn)
mnAttack[mnSize++] = i;
}
}
chColumn = mnAttack[rand()%mnSize];
P[chNode] = chColumn;
x = chNode, y = P[chNode];
if(x >= y) right = x-y;
else right = y-x+n;
x = chNode, y = n-P[chNode]+1;
if(x >= y) left = x-y;
else left = y-x+n;
if(column[P[chNode]] == 1) error++;
if(markRight[right] == 1) error++;
if(markLeft[left] == 1) error++;
column[P[chNode]]++, markRight[right]++, markLeft[left]++;
}
int step2() {
error = 0;
memset(column, 0, sizeof(column));
memset(markRight, 0, sizeof(markRight));
memset(markLeft, 0, sizeof(markLeft));
int i, x, y, right, left;
for(i = 1; i <= n; i++) {
x = i, y = P[i];
if(x >= y) right = x-y;
else right = y-x+n;
x = i, y = n-P[i]+1;
if(x >= y) left = x-y;
else left = y-x+n;
markRight[right]++;
markLeft[left]++;
column[y]++;
}
for(i = 0; i < 2*n; i++) {
if(markRight[i] > 1)
error++;
if(markLeft[i] > 1)
error++;
}
int times = 0;
while(error) {
times++;
/*printf("%d", P[1]);
for(i = 2; i <= n; i++)
printf(" %d", P[i]);
puts("");*/
step2a();
step2b();
/*printf("%d", P[1]);
for(i = 2; i <= n; i++)
printf(" %d", P[i]);
puts("");*/
/*printf("chNode %d column %d\n", chNode, chColumn);
printf("error %d\n", error);*/
// getchar();
/*if(times > 300) {
puts("unluck");
break;
}*/
}
//printf("%d\n", times);
return 1;
}
int main() {
srand(514);
int i;
puts("char ans[1005][5005] = {{""},{""}");
while(scanf("%d", &n) == 1) {
if(n <= 3) {
puts(",{\"Impossible\"}");
continue;
}
step1();
step2();
srand(rand());
printf(",{\"");
printf("%d", P[1]);
for(i = 2; i <= n; i++)
printf(" %d", P[i]);
puts("\"}");
}
puts("};");
return 0;
}
連 DLX+Random 都來湊一腳了,
心灰意冷了,速度不夠快。
#include <stdio.h>
#include <algorithm>
using namespace std;
struct DancingLinks {
int left, right, up, down, ch;
int rh; // 額外的 data
} DL[4000000 + 10001];
int s[10001], o[10001], head, size;
int n; // this problem need n for output process.
void remove(int c) {
DL[DL[c].right].left = DL[c].left;
DL[DL[c].left].right = DL[c].right;
int i, j;
for(i = DL[c].down; i != c; i = DL[i].down) {
for(j = DL[i].right; j != i; j = DL[j].right) {
DL[DL[j].down].up = DL[j].up;
DL[DL[j].up].down = DL[j].down;
s[DL[j].ch]--;
}
}
}
void resume(int c) {
int i, j;
for(i = DL[c].down; i != c; i = DL[i].down) {
for(j = DL[i].left; j != i; j = DL[j].left) {
DL[DL[j].down].up = j;
DL[DL[j].up].down = j;
s[DL[j].ch]++;
}
}
DL[DL[c].right].left = c;
DL[DL[c].left].right = c;
}
int found;
void print() {
int i;
int ans[1000];
for(i = 0; i < n; i++) {
ans[DL[o[i]].rh/n] = DL[o[i]].rh%n;
//printf("(%d, %d)", DL[o[i]].rh/n+1, DL[o[i]].rh%n+1);
}
//puts("");
printf("%d", ans[0]+1);
for(i = 1; i < n; i++)
printf(" %d", ans[i]+1);
puts("");
}
void dfs(int dep) {
if(found) return;
if(dep == n) { // just match for row&column
found = 1;
print();
return;
}
int tmp = 0xffff, c, i, j;
for(i = DL[head].right; i != head; i = DL[i].right) {
if(i > 2*n)
break;
if(s[i] <= tmp)
tmp = s[i], c = i;
}
remove(c);
for(i = DL[c].down; i != c; i = DL[i].down) {
o[dep] = i;
for(j = DL[i].right; j != i; j = DL[j].right)
remove(DL[j].ch);
dfs(dep+1);
if(found) return;
for(j = DL[i].left; j != i; j = DL[j].left)
resume(DL[j].ch);
}
resume(c);
}
int getnode(int u, int d, int l, int r) {
DL[size].up = u, DL[size].down = d;
DL[size].left = l, DL[size].right = r;
DL[u].down = DL[d].up = DL[l].right = DL[r].left = size;
return size++;
}
void newrow(int r[], int rn, int rh) {
int i, j, h;
for(i = 0; i < rn; i++) {
DL[size].ch = r[i], s[r[i]]++;
DL[size].rh = rh; // 額外的 data
if(i) {
j = getnode(DL[DL[r[i]].ch].up, DL[r[i]].ch, DL[h].left, h);
} else {
h = getnode(DL[DL[r[i]].ch].up, DL[r[i]].ch, size, size);
}
}
}
void init(int c) {// total column
size = 0;
head = getnode(0,0,0,0);
int i;
for(i = 1; i <= c; i++) {
getnode(i, i, DL[head].left, head);
DL[i].ch = i, s[i] = 0;
}
}
int main() {
int i, j, k;
int P[2005];
srand(514);
while(scanf("%d", &n) == 1) {
found = 0;
int column = n+n+2*(2*n-1); //row + cloumn + two diagonal
init(column);
int row[10], rn;
srand(rand());
for(i = 1; i <= 2*n; i++)
P[i] = i;
int times = rand()%5140+5140;
for(i = 1; i <= times; i++) {
j = rand()%(2*n)+1;
k = rand()%(2*n)+1;
swap(P[j], P[k]);
}
for(i = 1; i <= n; i++) {
for(j = 1; j <= n; j++) {
rn = 0;
//row[rn++] = i; // row
//row[rn++] = n+j; // column
row[rn++] = P[i];
row[rn++] = P[n+j];
if(i >= j) {
row[rn++] = i-j+1+(2*n);//left diagonal
} else {
row[rn++] = j-i+n+(2*n);//left diagonal
}
int tx = i, ty = n-j+1;
if(tx >= ty) {
row[rn++] = tx-ty+1+(2*n+2*n-1);//right diagonal
} else {
row[rn++] = ty-tx+n+(2*n+2*n-1);//right diagonal
}
//printf("(%d %d) %d %d %d %d\n", i, j, row[0], row[1], row[2], row[3]);
newrow(row, rn, (i-1)*n+j-1);
}
}
dfs(0);
if(!found)
puts("Impossible");
}
return 0;
}