#深搜+剪枝#洛谷 1074 靶形数独

本文介绍了一种使用深度优先搜索(DFS)结合剪枝策略来解决数独问题的方法,并通过计分矩阵计算最优解得分。该算法首先填充已知数字,然后根据行列及九宫格内剩余空位的分布情况选择最佳填充顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分析

深搜+剪枝,求出得分。
剪枝:已知数多的地方先填


代码

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
int in(){
	char c=getchar(); int ans=0;
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
const int MAXN=11;
const 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}};
int row[MAXN][MAXN],col[MAXN][MAXN],area[MAXN][MAXN],sdk[MAXN][MAXN];
int row_cnt[MAXN],col_cnt[MAXN],cnt,ans=-1;
inline int id(int i,int j){return (i-1)/3*3+1+(j-1)/3;}
inline int calc(){
    int tmp=0;
    for(int i=1;i<=9;++i)
        for(int j=1;j<=9;++j)
            tmp+=score[i][j]*sdk[i][j];
    return tmp;
}
void dfs(int r,int c,int cpl){    
    if(cpl==81){//填满
        ans=max(ans,calc());//记录最大答案
        return ;
    }
    for(int k=1;k<=9;++k){
        if(row[r][k]||col[c][k]||area[id(r,c)][k]) continue;//重复了
        row[r][k]=true;
        col[c][k]=true;
        area[id(r,c)][k]=true;
        row_cnt[r]++,col_cnt[c]++;
        sdk[r][c]=k;
        int tmpr=-1,nxt_r=0,tmpc=-1,nxt_c=0;
        for(int i=1;i<=9;++i)
            if(row_cnt[i]>tmpr&&row_cnt[i]<9)
                tmpr=row_cnt[i],nxt_r=i;
        for(int j=1;j<=9;++j)
            if(col_cnt[j]>tmpc&&(!sdk[nxt_r][j]))
                tmpc=col_cnt[j],nxt_c=j;
        dfs(nxt_r,nxt_c,cpl+1);//下一个地方
        row[r][k]=false;//回溯
        col[c][k]=false;
        area[id(r,c)][k]=false;
        row_cnt[r]--,col_cnt[c]--;
        sdk[r][c]=0;
    }
}
int main(){    
    for(int i=1;i<=9;++i){
        for(int j=1;j<=9;++j){
            sdk[i][j]=in();
            if(sdk[i][j]!=0){//已知数
                row[i][sdk[i][j]]=true;//行
                col[j][sdk[i][j]]=true;//列
                area[id(i,j)][sdk[i][j]]=true;//宫
                row_cnt[i]++,col_cnt[j]++;//行列已知数个数增加
                cnt++;//已知数个数增加
            }
        }
    }
    int tmpr=-1,r,tmpc=-1,c;
    for(int i=1;i<=9;++i)
        if(row_cnt[i]>tmpr&&row_cnt[i]<9)
            tmpr=row_cnt[i],r=i;
    for(int j=1;j<=9;++j)
        if(col_cnt[j]>tmpc&&(!sdk[r][j]))
            tmpc=col_cnt[j],c=j;
    dfs(r,c,cnt);//从最好填的地方开始
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值