靶形数独

Posted ainiyuling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了靶形数独相关的知识,希望对你有一定的参考价值。

题面

一个比较显然的事实是,在你玩数独的时候一般思路肯定是先把能确定的填上,比如样例一,第8行第8列,那个位置可能填的数特别少。

基于这种思路,我们先从容易确定的地方dfs,下一步走到下一个最容易确定的点,这样解答树能少枚举很多。

怎样判断一个点的确定度呢?当然是看看它的行填上了几个、列填上了几个、宫填上了几个了。但我比较懒就没判断宫,但可能是数据水?还是过了,虽然跑的不快,3000多ms

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define ll long long
int getint(){
    int x=0,f=1; char ch=getchar();
    while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f; ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();}
    return f*x;
}
const int MAXN=12;
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]=getint();
            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);
    cout<<ans<<endl;
}

  

以上是关于靶形数独的主要内容,如果未能解决你的问题,请参考以下文章

[NOIP2009]靶形数独 题解

洛谷 P1074靶形数独

洛谷——P1074 靶形数独

codevs1174 靶形数独

[Noip2009] 靶形数独

[NOIp 2009]靶形数独