sicily 1317. Sudoku

题目链接sicily 1317

这题咋一看以为不简单,因为第一感觉是时间复杂度很大,可想想写起来应该不难,于是飞快的写了个dfs。
结果是证明了我的感觉,超时了。确实是写起来容易的代码来对付时间复杂度很大很大的是会超时的。
只能做些优化了。看了别人的做法,也想到了之前马的周游一样的优化方法。从能够填写的数字个数最少的位置开始
深搜。原因是产生的树上端都是小,然后搜到下面的位置的话,一旦不符合很快就返回,结束掉,不会继续。避免说树的上端
很大,下端很小,结果即使下端返回了,上端要循环的次数还是很多。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int grid[9][9];
bool cols[9][10];
bool rows[9][10];
bool subgrid[9][10];
int firstAns[9][9]; //first solution
int ansCnt;
int puzzle[82];
int cnt[82];

void dfs()
{
    int x, y, j;
    int min = 81;
    for (j = 0; puzzle[j] != 88; ++j) {
        if (cnt[j] < cnt[min] && grid[puzzle[j]/9][puzzle[j]%9] == 0)
            min = j;
    }

    if (min == 81) {
        ++ansCnt;
        if (ansCnt == 1) {
            for (y = 0; y < 9; ++y)
                for (x = 0; x < 9; ++x)
                    firstAns[y][x] = grid[y][x];
        }
        return ;
    }

    x = puzzle[min]%9;
    y = puzzle[min]/9;

    for (j = 0; j < 9; j++) {
        cnt[x + j * 9]--;
        cnt[y * 9 + j]--;
    }
    int gridId = x/3 + y/3 * 3;

    for (int i = 1; i < 10; ++i) {        
        if (!cols[x][i] && !rows[y][i] && !subgrid[gridId][i]) {
            cols[x][i] = true;
            rows[y][i] = true;
            subgrid[gridId][i] = true;
            grid[y][x] = i;

            dfs();

            cols[x][i] = false;
            rows[y][i] = false;
            subgrid[gridId][i] = false;
            grid[y][x] = 0;
        }
    }

    for (j = 0; j < 9; j++) {
        cnt[x + j * 9]++;
        cnt[y * 9 + j]++;
    }
}

void init()
{
    ansCnt = 0;
    memset(cols, false, sizeof(cols));
    memset(rows, false, sizeof(rows));
    memset(subgrid, false, sizeof(subgrid));
    memset(cnt, 0, sizeof(cnt));
}

void find()
{
    int k = 0;

    for (int i = 0; puzzle[i] != 88 ; i++) {     
        int x = puzzle[i]%9;
        int  y = puzzle[i]/9;
        int gridId = x/3 + y/3 * 3;
        for (int j = 1; j < 10; j++) 
            if (!cols[x][j] && !rows[y][j] && !subgrid[gridId][j])
                cnt[i]++;
    }
    cnt[81] = 100;
}

int main()
{
//  freopen("input.txt","r",stdin);
    int t, num = 1;
    scanf("%d",&t);
    getchar();
    while (t--)
    {
        init();
        int x, y;

        //input
        int index = 0;
        for (y = 0; y < 9; ++y) {
            char in[10];
            gets(in);
            for (x = 0; x < 9; ++x) {
                if (in[x] == '_') {
                    grid[y][x] = 0;
                    puzzle[index++] = x + y*9;
                }
                else {
                    int dig = in[x] - '0';
                    int gridId = x/3 + y/3 * 3;
                    grid[y][x] = dig;
                    cols[x][dig] = true;
                    rows[y][dig] = true;
                    subgrid[gridId][dig] = true;                    
                }
            }
            //printf("\n"); 
        }
        puzzle[index] = 88;
        find();
        dfs();

        //output
        printf("Puzzle %d ",num++);
        if (ansCnt == 0)
            printf("has no solution\n");
        else if (ansCnt > 1)
            printf("has %d solutions\n",ansCnt);
        else {
            printf("solution is\n");
            for (y = 0; y < 9; ++y) {
                for (x = 0; x < 9; ++x)
                    printf("%d",firstAns[y][x]);
                printf("\n");
            }
        }
        if (t != 0)
            printf("\n");
    }
}                                 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值