• 高效的数独算法-位运算


    本篇通过一个数独问题,介绍一种高效的数独算法通过位运算。

    简介

    原文: https://my.oschina.net/u/1859679/blog/868056

    Java版本

    
    public class shudu {
    
        // 数独题目 ‘0’为空
    	private static int[] shuduNum = {0,0,3,6,0,0,0,0,1,0,7,0,0,8,0,0,0,0,6,0,0,3,0,9,7,0,0,7,5,0,0,4,0,6,0,3,0,0,0,0,6,7,8,9,0,0,9,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,1,5,0,9,0,0,0,0,4,0,0,1,0,0,0,0,0};
    	private static int[] tempNum = new int[81];
    	
    	// 列状态
    	private static int[] statusH = new int[9];
    	// 行状态
    	private static int[] statusV = new int[9];
    	// 九宫格状态
    	private static int[] statusB = new int[9];
    	// 上一次填数位置
    	private static int tempSp = 0 ;
    	
    	// 最大状态值 `1 1111 1111`
    	private static int STATUS_MAX_VALUE = 511;
    	
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		   
    		   // 打印出当前数独题目
    		   printSudoku(shuduNum) ;
    		   // 数独算法初始化
    		   initShudo() ;   
               // 开始解题		   
    		   tryAns2() ;
               // 打印出数独题目答案		   
    		   printSudoku(shuduNum) ;
    	}
    
    	private static void initShudo(){
    		
    		// 将所有的状态置为0
    		for(int i = 0;i<9;i++){
    			statusH[i] = 0;
    			statusV[i] = 0;
    			statusB[i] = 0;
    		}
    		
    		// 遍历数独题目中不为0的数,重置对应的行、列、九宫格状态
    		for(int i = 0;i<81;i++){
    		
    			 int indexH = i%9; 
    			 
    		   	 int indexV= i/9;	
    			 
    		   	 int indexB=((i/9)/3)*3+(i%9)/3;
    			 
    		   	 if(shuduNum[i] > 0 ){
    		   		int number = shuduNum[i];
    				// 通过位操作重置状态
    		   		markStatus(indexV,indexH,indexB,number);
    		   	 }
    		   	 
    			}
    		
    	}
    	
    	private static void markStatus(int indexV,int indexH,int indexB,int number){
    	     // 将第‘number’位,置位‘1’
    		if (number<1)return;
    		
    		/* ‘|=’ 位或 
    		 *  以`statusV[indexV]|=(1<<(number-1))` , `statusV[indexV] = 0 0000 0000` `number = 4`为例,
    		 *
    		 *  				  (1<<(number-1)) = 0 0000 0001 << 3 = 0 0000 1000
    		 *   statusV[indexV]|=(1<<(number-1)) = 0 0000 0000 & 0 0000 1000 = 0 0000 1000
    		 *
    		 */
    		 
    		statusV[indexV]|=(1<<(number-1));
        	statusH[indexH]|=(1<<(number-1));
        	statusB[indexB]|=(1<<(number-1));
    	}
    	
    	private static void tryAns2(){
    		
    		// 获取第一个空值 `0`
    		int sp = getNextBlank(-1);
    		
    		do{
    			int indexH =sp%9;      					
    	   	  	int indexV= sp/9;						
    	   	  	int indexB=((sp/9)/3)*3+(sp%9)/3;
    	   	  	
    	   	  	int skipValue  = shuduNum[sp];
    			
    	   	 resetStatus(indexV,indexH,indexB,skipValue);
    	   	 
    	   	int number = findNumber(indexV,indexH,indexB,skipValue);
    	   	
    	   	if(number == -1){
    	   		shuduNum[sp] = 0;
    	   		sp= pop() ;
    	   		if (sp==-1)
       	  		{
       	  			System.out.println("not cycle last sp,last sp ==-1");
       	  		}
    	   		continue;
    	   	}
    	   	
    	   	shuduNum[sp]=number;
       	  	// 标记状态
        	markStatus(indexV,indexH,indexB,number);
        	push(sp);
        	sp= getNextBlank(sp) ;
    		}while(sp >= 0 && sp < 81 );
    		
    		
    	}
    	
    	
    	private static int getNextBlank(int sp) {
    		   do {
    		      sp++ ;
    		   } while(sp<81 && shuduNum[sp]>0) ;
    		   return(sp) ;
    		}
    	
    	private static  void resetStatus(int indexV,int indexH,int indexB,int number){
    	
    		// 将第‘number’位,置位‘0’
    		if (number<1)
    		{
    			return;
    		}
    		
    		/* ‘&=’ 位与 
    		 *  以`statusV[indexV]&=~(1<<(number-1))` , `statusV[indexV] = 0 0000 1000` `number = 4`为例,
    		 *
    		 *  				  (1<<(number-1)) = 0 0000 0001 << 3 = 0 0000 1000
    		 *                   ~(1<<(number-1)) = 1 1111 0111
    		 *  statusV[indexV]&=~(1<<(number-1)) = 0 0000 1000 & 1 1111 0111 = 0 0000 0000
    		 *
    		 */
    	  	statusV[indexV]&=~(1<<(number-1));
    		statusH[indexH]&=~(1<<(number-1));
    		statusB[indexB]&=~(1<<(number-1));
    	}
    	
    	private static int findNumber(int indexV,int indexH,int indexB,int skipValue){
    		
    		int status = statusV[indexV]|statusH[indexH]|statusB[indexB];
    		if (skipValue>0){
    			status = status|((1<<skipValue)-1);							
    		}
    
    		if (status>=STATUS_MAX_VALUE)return -1;
    		
    		//把右起第一个0变成1
    		int nextStatus = status|(status+1);
    
    		//获取差值
    		int difValue = nextStatus^status;
    
    		//获取logn
    		for (int i = 0; i < 9; ++i){
    			if ((difValue>>i)==1)return i+1;
    			
    		}
    		return -1;
    	}
    	
    	private static int pop(){
    		if(tempSp<=0) return(-1) ;
    		   else return(tempNum[--tempSp]) ;
    	
    	}
    	
    	private static void push(int sp) {
    		   tempNum[tempSp++]= sp ;
    		}
    	
    	private static void  printSudoku(int[] prn) {
    		   for(int i=0; i<81; i++) {
    			   System.out.print(prn[i]+"  ");
    		      if(i%9==8) System.out.println("
    ");
    		   }
    		}
    
    }
    
    

    outPut

  • 相关阅读:
    python selenium-webdriver 执行js (八)
    python selenium-webdriver 等待时间(七)
    python selenium-webdriver 处理JS弹出对话框(六)
    python selenium-webdriver 元素操作之键盘操作(五)
    python selenium-webdriver 元素操作之鼠标操作(四)
    Jmeter 设置全部变量(十三)
    Jmeter 执行Python代码(十二)
    Jmeter Java Request (十一)
    Jenkins进阶-定时任务(17)
    JMeter 设置间隔时间(十)
  • 原文地址:https://www.cnblogs.com/chenjy1225/p/9662206.html
Copyright © 2020-2023  润新知