poj2676 2918 3074 3076 Sudoku

1 篇文章 0 订阅

poj 2676

题意:数独

思路:

1.dancing link

2. dfs(填写每一个九宫格) 加剪枝 回溯

  •   排除已出现的数字( sqr line column)
  •   收缩顺序 优先选取已知数字较多的方块搜索


#include <iostream>
#include<cstring>
#include <cstdio>
#define mem(a) memset(a,0,sizeof(a))
#define MAXNUM 9
using namespace std;
int sudoku[MAXNUM][MAXNUM];
int line[MAXNUM][MAXNUM+1],column[MAXNUM][MAXNUM+1];
int sqr[3][3][1+MAXNUM];
int cntsqr[3][3];
int esqr[3][3][2] = {{{3,3},{3,6},{3,9}},{{6,3},{6,6},{6,9}},{{9,3},{9,6},{9,9}}};
int cnt;
int maxX,maxY;
void init(){
  cnt = 0;
  mem(sudoku);
  mem(line);
  mem(column);
  mem(sqr);
  mem(cntsqr);
}
void picksqr(){
  maxX = maxY = -1;
  for (int i = 0;i<3;i++){
    for (int j = 0;j<3;j++){
      if (cntsqr[i][j] != MAXNUM){
        if (maxX == -1) {
          maxX = i,maxY = j;
        } else {
          if (cntsqr[i][j] > cntsqr[maxX][maxY])
            maxX = i,maxY = j;
        }
      }
    }
  }
}
void turn_back(int i,int j,int k){
  sudoku[i][j] = 0;
  line[i][k] =  column[j][k] = 0;
  sqr[i/3][j/3][k] = 0;
  cntsqr[i/3][j/3]--;
}
void update(int i,int j,int k){
  sudoku[i][j] = k;
  line[i][k] =  column[j][k] = 1;
  sqr[i/3][j/3][k] = 1;
  cntsqr[i/3][j/3]++;
}
bool dfs_sqr(int Sline,int Scolumn){
  int maxl = esqr[Sline/3][Scolumn/3][0],maxc = esqr[Sline/3][Scolumn/3][1];
  bool placed = false;
  for (int i = Sline;i<maxl && !placed;i++){
    for (int j = Scolumn;j<maxc && !placed;j++){
      if (sudoku[i][j] == 0){
        placed = true;
        for (int k = 1;k<=MAXNUM;k++){
          if (!sqr[i/3][j/3][k] && !line[i][k] && !column[j][k]){
            update(i,j,k);
            if(cntsqr[i/3][j/3] == MAXNUM){
              cnt++;
              if (cnt == 9) return true;
              picksqr();
              if (dfs_sqr(maxX*3,maxY*3)) return true;
              cnt--;
            }else {
              if (dfs_sqr(i,Scolumn)) return true;
            }
            turn_back(i,j,k);
          }
        }
      }
    }
  }
  return false;
}
int main()
{
  int test;
  scanf("%d",&test);
  while(test--){
    init();
    for (int i = 0;i<9;i++){
      char str[16];
      scanf("%s",str);
      for (int j = 0;j<9;j++){
        int num = str[j] - '0';
        if (num != 0) {
          update(i,j,num);
        }
        if ((i == 2 || i == 5 || i == 8 ) && (j == 2 || j == 5 || j == 8 )){
          if (cntsqr[i/3][j/3] == MAXNUM)
            cnt++;
       }
      }
    }
    picksqr();
    dfs_sqr(maxX*3,maxY*3);
    for (int i = 0;i<MAXNUM;i++){
      for(int j = 0;j<MAXNUM;j++)
        printf("%d",sudoku[i][j]);
      printf("\n");
    }
  }
  return 0;
}

poj 2918

略微修改上述代码可过

poj3074

上诉思路不可过

参考poj 3074 可过

poj 3076

上述思路均不可过

似乎需要使用dancing link

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值