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


  • 相关阅读:
    java去掉List中的重复值代码
    jquery 请求jsp传递json数据的方法
    jsp自定义标签分析
    jquery mouseout事件冒泡解决方法
    java split函数 对空的处理
    log4j使用感受
    mysql数据库主外键级联删除脚本RESTRICT --> CASCADE
    jquery 实现层级下拉框联动效果 代码
    JSP图片上传 公共工具类
    Apache和Nginx的对比
  • 原文地址:https://www.cnblogs.com/dollarzhaole/p/3188908.html
Copyright © 2011-2022 走看看