1 条题解

  • 1
    @ 2023-6-28 8:48:38

    一道比较复杂的深搜。

    首先我们用数组记录每个空的位置,然后从第一个空的位置开始搜,每填完一个空就转入下一个空的位置继续填……直到填完所有空。

    接下来是标记的问题,标记与八皇后类似:开四个二维数组分别表示行、列和两条斜线上对应的数字是否使用过。例如 hijh_{i_j} 表示在第 ii 行是否使用过数字 jj

    行列的标记很简单,斜线的标记复杂一些:通过观察发现,从左下到右上的斜线上的位置的行列坐标和是一定的,我们可以用 ci+jc_{i+j} 表示这样一条斜线的编号。而从左上到右下的斜线上的位置的行列坐标差是一定的,我们可以用 dij+nd_{i-j+n} 表示这样一条斜线的编号,+n+n 是为了防止负数。

    可以画个矩阵理解标记,具体详见代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,ans;
    char ch;
    bool h[10][10],l[10][10],c[11][10],d[18][10];
    vector<int> x,y;
    void dfs(int id){
        //当前正在填第id个空
        if (id==x.size()){
            ans++;
            return;
            //填写完毕,统计方案
        }
        int X=x[id],Y=y[id];
        for (int i=1;i<=n;i++){
            if (!h[X][i]&&!l[Y][i]&&!c[X+Y][i]&&!d[X-Y+n][i]){
                h[X][i]=1;
                l[Y][i]=1;
                c[X+Y][i]=1;
                d[X-Y+n][i]=1;
                dfs(id+1);
                h[X][i]=0;
                l[Y][i]=0;
                c[X+Y][i]=0;
                d[X-Y+n][i]=0;
                //又是一堆标记。。。。
            }
        }
    }
    int main(){
        cin>>n;
        for (int i=1;i<=n;i++){
            for (int j=1;j<=n;j++){
                cin>>ch;
                if (ch=='*'){
                    //记录每个空的位置
                    x.push_back(i);
                    y.push_back(j);
                    continue;
                }
                h[i][ch-'0']=1;
                l[j][ch-'0']=1;
                c[i+j][ch-'0']=1;
                d[i-j+n][ch-'0']=1;
                //一堆标记。。。
            }
        }
        dfs(0);
        cout<<ans;
        return 0;
    }
    
    • 1

    信息

    ID
    688
    时间
    1000ms
    内存
    16MiB
    难度
    3
    标签
    递交数
    28
    已通过
    19
    上传者