1、这道题我又SB了,N=11的时候怎么都输不出正确解,原因在于我算主对角线的时候只是将横纵相减,而忘了加n。。。注意数组的下标只能是非负数!不知道6到10的数据是怎么过的。。。
2、修改后,顺利AC~网上说用位运算什么的,不然要超时,我怎么没感觉。。。最后一个数据0.6s左右过的。。。
3、终于做完第一章了,不容易啊~对大牛来说很容易,可我是蒟蒻啊。。。
/*
ID:mrxy564
PROG:checker
LANG:C++
*/
#include<cstdio>
#include<cstring>
using namespace std;
int row[15];
bool col[15];
bool dia1[30],dia2[30];
int cnt=0;
void print(int n){
printf("%d",row[1]);
for(int i=2;i<=n;i++)
printf(" %d",row[i]);
printf("\n");
return;
}
void dfs(int now,int n){
if(now>n){
cnt++;
if(cnt<=3) print(n);
return;
}
for(int i=1;i<=n;i++)
if(!col[i]&&!dia1[now-i+n]&&!dia2[now+i]){
row[now]=i;
col[i]=true;
dia1[now-i+n]=true;
dia2[now+i]=true;
dfs(now+1,n);
dia2[now+i]=false;
dia1[now-i+n]=false;
col[i]=false;
}
return;
}
void init(){
memset(col,false,sizeof(col));
memset(dia1,false,sizeof(dia1));
memset(dia2,false,sizeof(dia2));
}
int main(){
freopen("checker.in","r",stdin);
freopen("checker.out","w",stdout);
int n;
scanf("%d",&n);
init();
dfs(1,n);
if(cnt>3) printf("%d\n",cnt);
return 0;
}
官方题解:
We use a recursive complete search to simply test all boards. The search proceeds by trying to put one checker in each row. We keep track of which columns and diagonals already have checkers on them in the "col", "updiag", and "downdiag" arrays.
Since we generate solutions in increasing order, we record the first 3 in the "sol" array.
Symmetry enables us to count the first half of the solutions double and avoid calculating the second half. An exception happens when N is odd; the odd row needs to be counted once.
The N>6 lines get the program out of trouble when N==6, because at that point, the first 3 solutions include one of the symmetric answers.
Since we number rows from 0 to N-1 rather than 1 to N, we need to add 1 to each digit as we print (in "printsol").
/* TASK: checker LANG: C */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #define MAXN 16 int n; int nsol, nprinted; char row[MAXN]; FILE *fout; void solution() { int i; for(i=0; i<n; i++) { if(i != 0) fprintf(fout, " "); fprintf(fout, "%d", row[i]+1); } fprintf(fout, "\n"); } /* Keep track of whether there is a checker on each column, and diagonal. */ char col[MAXN]; /* (i, j) -> j */ char updiag[2*MAXN]; /* (i, j) -> i+j */ char downdiag[2*MAXN]; /* (i, j) -> i-j + N */ /* * Calculate number of ways to place checkers * on each row of the board starting at row i and going to row n. */ void nway(i, lim) { int j; if(i == n) { nsol++; if (n > 6 && row[0] < n/2) nsol++; if (nprinted++ < 3) solution(); return; } for(j=0; j<lim; j++){ if(!col[j] && !updiag[i+j] && !downdiag[i-j+MAXN]){ row[i] = j; col[j]++; updiag[i+j]++; downdiag[i-j+MAXN]++; nway(i+1,n); col[j]--; updiag[i+j]--; downdiag[i-j+MAXN]--; } } } main(void) { FILE *fin = fopen("checker.in", "r"); fout = fopen("checker.out", "w"); fscanf(fin, "%d", &n); nway(0, n>6?(n+1)/2:n); fprintf(fout, "%d\n", nsol); exit (0); }
Clever Michael Rybak's Solution
The Ukraine's Michael Rybak removed the 'this row is used' search (which obviously at the end of the recursion is a lot of wasted iterating) and replaced it with a list of valid rows to use (which presumably has but a single element at the end of the recursion). His program runs almost 4x faster then N==13.
Program Checker; Var diagPLUS: Array[2..30] Of Boolean; diagMINUS: Array[-15..15] Of Boolean; sol: Array[1..15] Of ShortInt; i,n,found: Longint; stop: Boolean; next,prev: Array[0..16] Of ShortInt; sy: ShortInt; Procedure Search0(y:ShortInt); Var x,i:ShortInt; Begin If stop Then Exit; If y=n+1 Then Begin Inc(found); If found<4 Then Begin For i:=1 To n-1 Do Write(sol[i],' '); Writeln(sol[n]); End Else stop:=True; Exit; End; If sol[y]<>0 Then Begin Search0(y+1); Exit; End; x:=next[0]; While x<=n Do Begin If Not ((diagPLUS[x+y]) Or (diagMINUS[x-y])) Then Begin sol[y]:=x; diagPLUS[x+y]:=True; diagMINUS[x-y]:=True; next[prev[x]]:=next[x]; prev[next[x]]:=prev[x]; Search0(y+1); diagPLUS[x+y]:=False; diagMINUS[x-y]:=False; next[prev[x]]:=x; prev[next[x]]:=x; End; x:=next[x]; End; sol[y]:=0; End; Procedure Search; Var x:ShortInt; Begin If sy=n+1 Then Begin Inc(found); Exit; End; If sol[sy]<>0 Then Begin Inc(sy); Search; Dec(sy); Exit; End; x:=next[0]; While x<=n Do Begin If Not ((diagPLUS[x+sy]) Or (diagMINUS[x-sy])) Then Begin sol[sy]:=x; diagPLUS[x+sy]:=True; diagMINUS[x-sy]:=True; next[prev[x]]:=next[x]; prev[next[x]]:=prev[x]; Inc(sy); Search; Dec(sy); diagPLUS[x+sy]:=False; diagMINUS[x-sy]:=False; next[prev[x]]:=x; prev[next[x]]:=x; End; x:=next[x]; End; sol[sy]:=0; End; Procedure Search2(miny:Longint); Var x,y,i:ShortInt; curf:Longint; Begin x:=n Div 2+1; For y:=miny To n Div 2 Do If Not (diagPLUS[x+y] Or diagMINUS[x-y]) Then Begin curf:=found; sol[y]:=x; diagPLUS[x+y]:=True; diagMINUS[x-y]:=True; next[prev[x]]:=next[x]; prev[next[x]]:=prev[x]; sy:=1; Search; If y>miny Then found:=found+(found-curf); sol[y]:=0; diagPLUS[x+y]:=False; diagMINUS[x-y]:=False; next[prev[x]]:=x; prev[next[x]]:=x; End; End; Procedure Search1; Var x,y,i:ShortInt; Begin y:=n Div 2+1; For x:=1 To n Div 2 Do Begin sol[y]:=x; diagPLUS[x+y]:=True; diagMINUS[x-y]:=True; next[prev[x]]:=next[x]; prev[next[x]]:=prev[x]; Search2(x); diagPLUS[x+y]:=False; diagMINUS[x-y]:=False; next[prev[x]]:=x; prev[next[x]]:=x; End; sol[y]:=0; found:=found*4; x:=n Div 2+1; sol[y]:=x; diagPLUS[x+y]:=True; diagMINUS[x-y]:=True; next[prev[x]]:=next[x]; prev[next[x]]:=prev[x]; sy:=1; Search; End; Begin Assign(Input,'checker.in'); Reset(Input); Assign(Output,'checker.out'); Rewrite(Output); Read(n); found:=0; FillChar(diagPLUS,SizeOf(diagPLUS),False); FillChar(diagMINUS,SizeOf(diagMINUS),False); FillChar(sol,SizeOf(sol),0); For i:=0 To n+1 Do Begin prev[i]:=i-1; next[i]:=i+1; End; If n Mod 2=0 Then Begin stop:=False; Search0(1); sy:=1; found:=0; Search; End Else Begin stop:=False; Search0(1); found:=0; Search1; End; Writeln(found); Close(Output); End.
Clever Romanian Solution
Submitted by several from Romania, this solution uses bitmasks instead of a list to speed searching:
#include <stdio.h> #include <stdlib.h> #include <fstream.h> #define MAX_BOARDSIZE 16 typedef unsigned long SOLUTIONTYPE; #define MIN_BOARDSIZE 6 SOLUTIONTYPE g_numsolutions = 0; void Nqueen(int board_size) { int aQueenBitRes[MAX_BOARDSIZE]; /* results */ int aQueenBitCol[MAX_BOARDSIZE]; /* marks used columns */ int aQueenBitPosDiag[MAX_BOARDSIZE]; /* marks used "positive diagonals" */ int aQueenBitNegDiag[MAX_BOARDSIZE]; /* marks used "negative diagonals" */ int aStack[MAX_BOARDSIZE + 2]; /* a stack instead of recursion */ int *pnStack; int numrows = 0; /* numrows redundant - could use stack */ unsigned int lsb; /* least significant bit */ unsigned int bitfield; /* set bits denote possible queen positions */ int i; int odd = board_size & 1; /* 1 if board_size odd */ int board_m1 = board_size - 1; /* board size - 1 */ int mask = (1 << board_size) - 1; /* N bit mask of all 1's */ aStack[0] = -1; /* sentinel signifies end of stack */ for (i = 0; i < (1 + odd); ++i) { bitfield = 0; if (0 == i) { int half = board_size>>1; /* divide by two */ bitfield = (1 << half) - 1; pnStack = aStack + 1; /* stack pointer */ aQueenBitRes[0] = 0; aQueenBitCol[0] = aQueenBitPosDiag[0] = aQueenBitNegDiag[0] = 0; } else { bitfield = 1 << (board_size >> 1); numrows = 1; /* prob. already 0 */ aQueenBitRes[0] = bitfield; aQueenBitCol[0] = aQueenBitPosDiag[0] = aQueenBitNegDiag[0] = 0; aQueenBitCol[1] = bitfield; aQueenBitNegDiag[1] = (bitfield >> 1); aQueenBitPosDiag[1] = (bitfield << 1); pnStack = aStack + 1; /* stack pointer */ *pnStack++ = 0; /* row done -- only 1 element & we've done it */ bitfield = (bitfield - 1) >> 1; /* bitfield -1 is all 1's to the left of the single 1 */ } for (;;) { lsb = -((signed)bitfield) & bitfield; /* this assumes a 2's complement architecture */ if (0 == bitfield) { bitfield = *--pnStack; /* get prev. bitfield from stack */ if (pnStack == aStack) /* if sentinel hit.... */ break; --numrows; continue; } bitfield &= ~lsb; /* bit off -> don't try it again */ aQueenBitRes[numrows] = lsb; /* save the result */ if (numrows < board_m1) { /* more rows to process? */ int n = numrows++; aQueenBitCol[numrows] = aQueenBitCol[n] | lsb; aQueenBitNegDiag[numrows] = (aQueenBitNegDiag[n] | lsb) >> 1; aQueenBitPosDiag[numrows] = (aQueenBitPosDiag[n] | lsb) << 1; *pnStack++ = bitfield; bitfield = mask & ~(aQueenBitCol[numrows] | aQueenBitNegDiag[numrows] | aQueenBitPosDiag[numrows]); continue; } else { ++g_numsolutions; bitfield = *--pnStack; --numrows; continue; } } } g_numsolutions *= 2; } int main(int argc, char** argv) { ifstream f("checker.in"); ofstream g("checker.out"); long boardsize,s[20],ok,k,i,sol=0; f>>boardsize; Nqueen (boardsize); k=1; s[k]=0; while (k>0) { ok=0; while(s[k]<boardsize && !ok) { ok=1; s[k]++; for(i=1;i<k;i++) if(s[i]==s[k] || abs(s[k]-s[i])==abs(k-i)) ok=0; } if(sol!=3) if(!ok) k--; else if(k==boardsize) { for(i=1;i<boardsize;i++) { for(int j=1;j<=boardsize;j++) if(s[i]==j) g<<j<<" "; } for(i=1;i<=boardsize;i++) if(s[boardsize]==i) g<<i; g<<"\n"; sol++; } else { k++; s[k]=0; } else break; } g<<g_numsolutions<<"\n"; f.close(); g.close(); return 0; }