1. 程式人生 > >[NOIP2009] 靶形數獨(搜索)

[NOIP2009] 靶形數獨(搜索)

char class 也不能 tps for 完數 區域 read str

P1074 靶形數獨

題目描述

小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨遊戲,好勝的他們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向 Z 博士請教,Z 博士拿出了他最近發明的“靶形數獨”,作為這兩個孩子比試的題目。

靶形數獨的方格同普通數獨一樣,在 9 格寬× 9 格高的大九宮格中有 9 個 3 格寬× 3 格高的小九宮格(用粗黑色線隔開的)。在這個大九宮格中,有一些數字是已知的,根據這些數字,利用邏輯推理,在其他的空格上填入 1 到 9 的數字。每個數字在每個小九宮格內不能重復出現,每個數字在每行、每列也不能重復出現。但靶形數獨有一點和普通數獨不同,即每一個方格都有一個分值,而且如同一個靶子一樣,離中心越近則分值越高。(如圖)

技術分享圖片

上圖具體的分值分布是:最裏面一格(黃色區域)為 10 分,黃色區域外面的一圈(紅色區域)每個格子為 9 分,再外面一圈(藍色區域)每個格子為 8 分,藍色區域外面一圈(棕色區域)每個格子為 7 分,最外面一圈(白色區域)每個格子為 6 分,如上圖所示。比賽的要求是:每個人必須完成一個給定的數獨(每個給定數獨可能有不同的填法),而且要爭取更高的總分數。而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和

總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和。如圖,在以下的這個已經填完數字的靶形數獨遊戲中,總分數為 2829。遊戲規定,將以總分數的高低決出勝負。

技術分享圖片

由於求勝心切,小城找到了善於編程的你,讓你幫他求出,對於給定的靶形數獨,能夠得到的最高分數。

輸入輸出格式

輸入格式:

一共 行。每行 9個整數(每個數都在 0?9的範圍內),表示一個尚未填滿的數獨方格,未填的空格用“ 0 ”表示。每兩個數字之間用一個空格隔開。

輸出格式:

輸出共 1 行。輸出可以得到的靶形數獨的最高分數。如果這個數獨無解,則輸出整數 ?1 。

輸入輸出樣例

輸入樣例#1: 復制

7 0 0 9 0 0 0 0 1
1 0 0 0 0 5 9 0 0
0 0 0 2 0 0 0 8 0
0 0 5 0 2 0 0 0 3
0 0 0 0 0 0 6 4 8
4 1 3 0 0 0 0 0 0
0 0 7 0 0 2 0 9 0
2 0 1 0 6 0 8 0 4
0 8 0 5 0 4 0 1 2

輸出樣例#1: 復制

2829

輸入樣例#2: 復制

0 0 0 7 0 2 4 5 3
9 0 0 0 0 8 0 0 0
7 4 0 0 0 5 0 1 0
1 9 5 0 8 0 0 0 0
0 7 0 0 0 0 0 2 5
0 3 0 5 7 9 1 0 8
0 0 0 6 0 1 0 0 0
0 6 0 9 0 0 0 0 1
0 0 0 0 0 0 0 0 6

輸出樣例#2: 復制

2852

說明

【數據範圍】

40%的數據,數獨中非 0 數的個數不少於 30 。

80%的數據,數獨中非 0數的個數不少於 26 。

100%的數據,數獨中非 0 數的個數不少於 24。

NOIP 2009 提高組 第四題


題解

因為搜索太差了所以來學搜索.jpg
這道題目怎麽寫呢?
假如只是要你去填一個數獨。你會怎麽搜?
用三個數組記錄每行每列和每個九宮格內的數都用了多少了。
然後從1,1搜到9,9。
就有80分了。
這時候我們來想一想剪枝。
怎麽剪?
在自己玩數獨(雖然我沒玩過)的時候。
我們肯定優先選擇數字多的地方開始填數,因為這樣可以確定較多選定的狀態(讓其他組選擇數字時,選擇的機會較少)。
選擇行列或者九宮格其中任意一個都是可以的。


代碼

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int map[11][11],l[11][11],h[11][11];
int v[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 bl[11][11],ans=0;
struct node{
    int vi,id;
}ch[11];
int read()
{
    int x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

void solve(){
    if(map[ch[9].id][9]){
        int sum=0;
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++)
            sum+=map[i][j]*v[i][j];
        }
        ans=max(sum,ans);
    }
    return ;
}

void dfs(int x,int y){
    if(map[ch[x].id][y]){
        if(x==9&&y==9){solve();return ;}
        if(y==9)dfs(x+1,1);else dfs(x,y+1);
    }
    else {
        for(int i=1;i<=9;i++){
            if(!h[ch[x].id][i]&&!l[y][i]&&!bl[(ch[x].id-1)/3*3+(y-1)/3+1][i]){
                h[ch[x].id][i]=1;l[y][i]=1;map[ch[x].id][y]=i;
                bl[(ch[x].id-1)/3*3+(y-1)/3+1][i]=1;
                if(x==9&&y==9)solve();if(y==9)dfs(x+1,1);else dfs(x,y+1);
                h[ch[x].id][i]=0;l[y][i]=0;map[ch[x].id][y]=0;
                bl[(ch[x].id-1)/3*3+(y-1)/3+1][i]=0;
            }
        }
    }
}

bool cmp(node a,node b){
    return a.vi>b.vi;
}

int main()
{
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++){
        map[i][j]=read();
        if(map[i][j])
        {
            h[i][map[i][j]]=1;
            l[j][map[i][j]]=1;
            bl[(i-1)/3*3+(j-1)/3+1][map[i][j]]=1;
            ch[i].vi++;
        }
        ch[i].id=i;
        }
    }
    sort(ch+1,ch+9+1,cmp);
    dfs(1,1);
    printf("%d\n",ans==0?-1:ans);
    return 0;
}

[NOIP2009] 靶形數獨(搜索)