蓝桥杯第100 题 九宫幻方 DFS 全排列 C++ 解题思维

题目

九宫幻方icon-default.png?t=N7T8https://www.lanqiao.cn/problems/100/learning/?page=1&first_category_id=1&name=%E4%B9%9D

思路和解题方法  一 (DFS)

  1. 首先,定义了一些全局变量和数组。vis数组用于标记已经出现过的数字,a数组用于存储数独的初始状态和中间状态,ans数组用于存储找到的解决方案,p数组用于存储空白格子的坐标,n表示空白格子的数量,cnt记录解决方案的数量。

  2. check()函数用于检查当前填充的数字是否满足数独的规则。它首先计算对角线上的元素之和,然后检查每行和每列的和是否相等,并返回一个布尔值表示结果。

  3. dfs()函数是核心部分,使用递归实现深度优先搜索。它从第一个空白格子开始填充数字,每次填充一个数字后,递归调用自身继续填充下一个空白格子,直到所有空白格子都填充完毕。如果找到了符合数独规则的解决方案,则将其记录在ans数组中,并增加cnt的计数。

  4. main()函数中,首先读入数独的初始状态,并初始化相关变量。然后调用dfs()函数进行搜索。最后,根据搜索结果输出解决方案或提示"Too Many"表示找到了多个解决方案。

需要注意的是,该程序假设输入的数独有唯一解或没有解。如果存在多个解,则只会输出其中一个解。如果不存在解,则输出"Too Many"表示无法确定唯一解。

c++ 代码  1

#include<bits/stdc++.h>
using namespace std;

int vis[10],a[5][5],ans[5][5];
// vis数组用来标记数字是否使用过,a数组记录数独题目的矩阵,ans数组用来存储解决方案
int n=1,cnt;
pair<int ,int>p[10];
// p数组用来存储空白格的坐标,n记录空白格的个数
bool check(){
    int sum=a[1][1]+a[2][2]+a[3][3];
    // 先计算左上到右下的斜线上的数字之和
    if(sum!=a[1][3]+a[2][2]+a[3][1]) return false;
    // 再计算右上到左下的斜线上的数字之和,如果不相等,则不是数独的解
    for(int i=1;i<=3;i++){
    int tmp1=0,tmp2=0;
    for(int j=1;j<=3;j++)tmp1+=a[i][j],tmp2+=a[j][i];//行和列的和相等 
        if(tmp1!=sum||tmp2!=sum) return false;
    }
    // 分别计算每行每列的数字之和,如果与斜线上的数字之和不相等,则不是数独的解
    return true;
} 

void dfs(int now){
    if(now>=n){
        if(check()){
            cnt++;
            for(int i=1;i<=3;i++)
                for(int j=1;j<=3;j++)
                    ans[i][j]=a[i][j];
            // 如果当前数独矩阵是解,则令ans数组等于当前矩阵
        }
        return;
    }
    int x=p[now].first,y=p[now].second;
    for(int k=1;k<=9;k++)
    {
        if(vis[k])continue;
        a[x][y]=k;
        vis[k]=1;
        dfs(now+1);
        a[x][y]=0;
        vis[k]=0;
        // 搜索之前先标记数字已经使用过,搜索完之后再回溯
    }
}

int main()
{
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++){
            cin>>a[i][j];
            if(!a[i][j])p[n++]=make_pair(i,j);
            // 记录空白格的坐标
            vis[a[i][j]]=1;    
            // 标记数字已经使用过
        }
    dfs(1);//从第一个空白格开始搜索
    if(cnt==1){
        for(int i=1;i<=3;i++)
            for(int j=1;j<=3;j++)
                cout<<ans[i][j]<<" \n"[j==3];
            }
    else cout<<"Too Many\n";
    // 如果有多个解,则输出"Too Many"
    return 0;
 }

 思路和解题方法   二 (全排列)

  1. 从标准输入中读入一个包含9个整数的数组a。
  2. 使用next_permutation函数生成arr数组的全排列,并逐个判断是否满足数独的条件。
  3. 如果某个排列满足数独条件,并且与输入数组a匹配,则将该排列赋值给数组a,并增加计数器ans的值。
  4. 最后根据计数器ans的值输出结果。如果有且仅有一个解,则输出解;如果有多个解,则输出"Too Many"。

c++ 代码

#include<iostream>
#include<algorithm>
#include<bits/stdc++.h> //包含一些常用的头文件,例如vector、string等
using namespace std;

int a[10]; //定义一个长度为10的数组a,用于存储输入的数独初始状态
int ans = 0; //计数器,用于存储符合数独条件的解的个数
int arr[10] = {1,2,3,4,5,6,7,8,9}; //定义一个长度为10的数组arr,用于生成全排列

//检查当前排列是否符合数独条件
bool check(int a[])
{
    int a1=a[0]+a[1]+a[2];
    int a2=a[3]+a[4]+a[5];
    int a3=a[6]+a[7]+a[8];
    int a4=a[0]+a[3]+a[6];
    int a5=a[1]+a[4]+a[7];
    int a6=a[2]+a[5]+a[8];
    int a7=a[2]+a[4]+a[6];
    int a8=a[0]+a[4]+a[8];

    if(a1==a2&&a2==a3&&a3==a4&&a4==a5&&a5==a6&&a6==a7&&a7==a8) //如果8个和相等,则返回true
    {
        return true;
    }
    return false; //否则返回false
}

int main()
{
    for(int i = 0;i<9;i++) //读入初始数独状态
    {
        cin>>a[i];
    }

    while(next_permutation(arr,arr+9)){ //生成arr数组的全排列,逐个检查是否符合数独条件
        if(check(arr)) //如果符合数独条件
        {
            bool y = true;
            for(int i = 0;i<9;i++)
            {
                if(a[i]!=0&&a[i]!=arr[i]) //如果输入的数独状态不为0且与当前排列不一致,则说明不是想要的解
                {
                    y = false; //设置标志y为false
                }
            }
            if(y) //如果当前排列与输入的数独状态匹配
            {
                for(int i = 0;i<9;i++) //将当前排列赋值给数组a
                {
                    a[i] = arr[i];
                }
                ans++; //计数器ans加1
            }
        }
    }

    if(ans == 1) //如果只有一个解,则输出该解
    {
        int cnt = 0; //计数器cnt,用于输出格式控制
        for(int i = 0;i<9;i++)
        {
            if(cnt==3)
            {
                cout<<endl; //每输出三个数字换行
                cnt = 0;
            }
            cout<<a[i]<<" "; //输出数独解
            cnt++; //计数器加1
        }
    }else { //如果有多个解,则输出"Too Many"
        printf("Too Many");
    }
    return 0;
}

知识点解释

next_permutation() 全排列

next_permutation()是一个函数,通常在编程语言中用于生成给定序列的下一个排列。它可以按照字典序(升序)生成给定序列的下一个排列,并将其更新为下一个排列。

具体而言,next_permutation()函数接受一个序列作为参数,并将该序列重排为下一个字典序更大的排列。如果没有下一个更大的排列,则将序列重排为最小的(升序)排列。该函数返回一个布尔值,指示是否成功生成了下一个排列。

下面是一个示例,展示了如何使用next_permutation()函数来生成给定序列的所有排列:

#include <iostream>
 #include <algorithm>
 using namespace std;
 ​
 int main() {
     int arr[] = {1, 2, 3};
 ​
     // 生成并打印所有排列
     do {
         for (int i = 0; i < 3; i++) {
             cout << arr[i] << " ";
         }
         cout << endl;
     } while (next_permutation(arr, arr + 3));
 ​
     return 0;
 }

输出结果将是:

 1 2 3
 1 3 2
 2 1 3
 2 3 1
 3 1 2
 3 2 1

这个例子展示了如何使用next_permutation()函数生成给定序列的所有排列,并将它们打印出来。每次调用next_permutation()函数时,原始数组会被修改为下一个排列,直到没有更多的排列可生成为止。

需要注意的是,next_permutation()函数在不同的编程语言和库中可能有略微不同的实现方式,但其基本功能是相似的:生成给定序列的下一个排列。

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一份使用C++实现宽度优先搜索求解重排九宫的代码,具体注释在代码中: ```cpp #include <iostream> #include <queue> #include <map> using namespace std; struct State { int board[3][3]; // 保存当前状态的棋盘 int spaceX, spaceY; // 空格的位置 int depth; // 当前状态的深度 int heuristic; // 当前状态的启发值 string history; // 保存到达当前状态的操作序列 bool operator<(const State& other) const { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board[i][j] != other.board[i][j]) { return board[i][j] < other.board[i][j]; } } } return false; } }; const int dx[] = {1, 0, -1, 0}; const int dy[] = {0, 1, 0, -1}; int getHeuristic(State& state) { int sum = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (state.board[i][j] == 0) { continue; } int x = (state.board[i][j] - 1) / 3; int y = (state.board[i][j] - 1) % 3; sum += abs(x - i) + abs(y - j); } } return sum; } bool isSolved(State& state) { int value = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (state.board[i][j] != value) { return false; } value++; } } return true; } void printBoard(State& state) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { cout << state.board[i][j] << " "; } cout << endl; } cout << endl; } int main() { State initial; // 初始化初始状态 for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { cin >> initial.board[i][j]; if (initial.board[i][j] == 0) { initial.spaceX = i; initial.spaceY = j; } } } initial.depth = 0; initial.heuristic = getHeuristic(initial); initial.history = ""; queue<State> q; map<State, bool> visited; q.push(initial); visited[initial] = true; while (!q.empty()) { State current = q.front(); q.pop(); if (isSolved(current)) { cout << current.history << endl; break; } for (int i = 0; i < 4; i++) { int nx = current.spaceX + dx[i]; int ny = current.spaceY + dy[i]; if (nx < 0 || nx >= 3 || ny < 0 || ny >= 3) { continue; } State next = current; // 移动空格 swap(next.board[current.spaceX][current.spaceY], next.board[nx][ny]); next.spaceX = nx; next.spaceY = ny; next.depth++; next.heuristic = getHeuristic(next); next.history += char('0' + i); if (!visited[next]) { q.push(next); visited[next] = true; } } } return 0; } ``` 其中,State结构体表示状态,包括当前的棋盘、空格的位置、当前状态的深度、当前状态的启发值和到达当前状态的操作序列。isSolved函数判断当前状态是否为目标状态,getHeuristic函数计算当前状态的启发值,printBoard函数用于打印棋盘。在主函数中,使用宽度优先搜索求解重排九宫,每次移动空格时生成新的状态,并计算其启发值,如果该状态未被访问过,则加入队列中。如果搜索到目标状态,则输出操作序列并退出循环。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值