洛谷 P1074【靶形数独】(DFS)

用三维数组来记录当前这个数字有没有被行或者列或者小九宫格用过,同时优化一下搜索顺序,我们从0少的那一行开始搜索,减小搜索树分支,这个优化是比较大的。

 

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
P p[100];
int a[15][15],cnt,ans=-1;
bool vis[3][15][15];//第一维0表示行 1表示列 2表示9宫格
int score[10][10]//分数数组
{
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 6, 6, 6, 6, 6, 6, 6, 6, 6 },
    { 0, 6, 7, 7, 7, 7, 7, 7, 7, 6 },
    { 0, 6, 7, 8, 8, 8, 8, 8, 7, 6 },
    { 0, 6, 7, 8, 9, 9, 9, 8, 7, 6 },
    { 0, 6, 7, 8, 9, 10, 9, 8, 7, 6 },
    { 0, 6, 7, 8, 9, 9, 9, 8, 7, 6 },
    { 0, 6, 7, 8, 8, 8, 8, 8, 7, 6 },
    { 0, 6, 7, 7, 7, 7, 7, 7, 7, 6 },
    { 0, 6, 6, 6, 6, 6, 6, 6, 6, 6 },
};
struct node{
    int cnt_0, row;
    bool operator<(const node &other)const{
        return cnt_0 < other.cnt_0;
    }
}r[11];
int getScore()//得到总分数
{
    int sum = 0;
    for (int i = 1; i <= 9; i++)
        for (int j = 1; j <= 9; j++)
            sum += a[i][j] * score[i][j];
    return sum;
}
int GetGrid(int i, int j)//得到坐标i,j所在的9宫格的编号
{
    return (i - 1) / 3 * 3 + (j - 1) / 3 + 1;
}
void dfs(int k)
{
    if (k == cnt) {
        ans = max(ans, getScore());
        return;
    }
    int x = p[k].first, y = p[k].second;
    for (int i = 1; i <= 9; i++)
    {
        if (!vis[0][x][i] && !vis[1][y][i] && !vis[2][GetGrid(x, y)][i])//如果未使用
        {
            vis[0][x][i] = vis[1][y][i] = vis[2][GetGrid(x, y)][i] = true;
            a[x][y] = i;
            dfs(k + 1);
            vis[0][x][i] = vis[1][y][i] = vis[2][GetGrid(x, y)][i] = false;//回溯
            a[x][y] = 0;
        }
    }
}
int main()
{
    for (int i = 1; i <= 9; i++)
    {
        int cnt_0 = 0;//记录这一行0的个数
        for (int j = 1; j <= 9; j++)
        {
            scanf("%d", &a[i][j]);
            if (!a[i][j]) cnt_0++;
            else{
                vis[0][i][a[i][j]] = true;//记录已经使用
                vis[1][j][a[i][j]] = true;
                vis[2][GetGrid(i, j)][a[i][j]] = true;
            }
        }
        r[i].row = i, r[i].cnt_0 = cnt_0;
    }
    sort(r + 1, r + 10);//排序,从0少的行开始搜索
    for (int i = 1; i <= 9; i++)
    {
        for (int j = 1; j <= 9; j++)
        {
            int row = r[i].row;
            if (!a[row][j])
            {
                p[cnt].first =row, p[cnt].second = j;//保存坐标,这就是我们的搜索顺序
                cnt++;//待填数字的个数
            }
        }
    }
    dfs(0);
    return 0;
}

 

posted @ 2019-03-06 22:55  TLE自动机  阅读(229)  评论(0编辑  收藏  举报