zoukankan      html  css  js  c++  java
  • USACO section 1.5.4 Checker Challenge

    1. 第一次做位运算的题,参考了这段经典代码(n皇后问题):

    void Queen(int row, int ld, int rd)
    {
        int pos, p;
        int upperlim = (1 << n) - 1;
        if (row != upperlim)
        {
            pos = upperlim & ~(row | ld | rd);
            while (pos != 0)
            {
                p = pos & -pos;  // v & -v 的作用就是取出右起连续的 0 以及首次出现的 1
                pos -= p;
                Queen(row + p, (ld + p) << 1, (rd + p) >> 1);
            }
        }
        else ++sum;
    }

    2. 以下是代码:

    /*
    ID: dollar4
    PROG: checker
    LANG: C++
    */
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <algorithm>
    #include <cstring>
    #include <iomanip>
    #include <cmath>
    
    using namespace std;
    ofstream fout ("checker.out");
    ifstream fin ("checker.in");
    int n;
    int step[50];
    int maxx;
    int cnt = 0;
    void dfs(long long row, long long ld, long long rd, int depth)
    {
        if (depth == n)
        {
            cnt++;
            if (cnt <= 3)
            {
                for (int i = 0; i < depth - 1; i++)
                    fout << step[i] << ' ';
                fout << step[depth - 1] << endl;
            }
            return;
        }
        long int pos, p;
        pos = (row | ld | rd) & maxx;
        while (pos != maxx)
        {
            p = (~pos) & (pos + 1) & maxx;
            if (cnt <= 2)
                step[depth] = (int)log2((double)p) + 1;
            dfs(row + p, (ld + p) << 1, (rd + p) >> 1, depth + 1);
            pos = (pos| p) & maxx;
        }
    }
    int main()
    {
        fin >> n;
        maxx = (1 << n) - 1;
        dfs(0, 0, 0, 0);
        fout << cnt << endl;
        return 0;
    }
    /*
    void Queen(int row, int ld, int rd)
    {
        int pos, p;
        int upperlim = (1 << n) - 1;
        if (row != upperlim)
        {
            pos = upperlim & ~(row | ld | rd);
            while (pos != 0)
            {
                p = pos & -pos;  // v & -v 的作用就是取出右起连续的 0 以及首次出现的 1
                pos -= p;
                Queen(row + p, (ld + p) <> 1);
            }
        }
        else ++sum;
    }
    */
    

    3. 官方参考代码:

    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 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;
    }


  • 相关阅读:
    Meteor会话
    Meteor事件
    Meteor表单
    Meteor集合
    Meteor模板
    Visual Studio 必备神器
    DB2 DATE类型在显示的时候,带有00:00:00,去掉的方法,使用VARCHAR()函数
    SQL 递归查询
    程序员最艰巨的十大任务
    Windows 7,64位机器上安装DB2 7.2+FP7
  • 原文地址:https://www.cnblogs.com/dollarzhaole/p/3188908.html
Copyright © 2011-2022 走看看