NOIP2009 靶形數獨 題解

2021-07-22 07:22:30 字數 3002 閱讀 2615

【題目名稱】靶形數獨

【題目**】noip2009

【時間限制】2000ms

【空間限制】128m

問題描述

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

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

上圖具體的分值分布是:最裡面一格(黃色區域)為10分,黃色區域外面的一圈(紅色區域)每個格仔為9分,再外面一圈(藍色區域)每個格仔為8分,藍色區域外面一圈(棕色區域)每個格仔為7分,最外面一圈(白色區域)每個格仔為6分,如上圖所示。比賽的要求是:每個人必須完成乙個給定的數獨(每個給定數獨有可能有不同的填法),而且要爭取更高的總分數。而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和。如圖,在以下這個已經填完數字的靶形數獨遊戲中,總分為2829。遊戲規定,將以總分數的高低決出勝負。

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

輸入格式

輸入檔名為sudoku.in。

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

輸出格式

輸出檔案sudoku.out共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

【輸入樣例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

樣例輸出

【輸出樣例1】

2829

【輸出樣例2】

2852

提示【資料範圍】

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

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

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

【題解】

雖然有大神告訴我,處理數獨問題用跳舞鏈很快,不過,我的確不會這些高深的演算法。其實採取深度優先搜尋就可以了。然而也不能太過於暴力,我們多少要加一點優化。實際上,我的解法是屬於啟發式搜尋。

回憶一下,當我們用人腦解數獨時,我們用的什麼策略?排除法!我們先會排除掉不可能的數。並且我們總是會從可行解較少的格仔開始填數,這樣會大大減少列舉次數。於是這就是啟發式搜尋的根據了。我們依照剩餘可行解的數量來確定搜尋的順序,可行解越少的格仔,越優先討論。當然我們可以估計剩餘格仔的最高得分,如果這個分數加上當前得分仍不超過已知最優解,則可以直接return,因為得出的解不可能再是最優解了。

思路很簡單粗暴,但**並不好寫,下面給出我的**。

【參考**】

#include#include#define inf 0x3fffffff

int a[10][10],ans=0;//a記錄數陣,ans記錄最終答案

int area(int x,int y)

//確定(x,y)所在的小九宮格

int minn(int a,int b)

int abs(int x)

int score(int x,int y)

//計算(x,y)的分數

bool h[10][10],l[10][10],area[10][10];//h--行,l--列,area--小九宮格;h[i][j]=1,表示第i行能夠填入數字j,其餘以此類推

void read_in()

} return ;

}//讀入,計分

bool wujie=0;

void init()

} for(int i=1;i<=9;i++)

else

}} }

return ;

}//初始化

bool f=0;

void dfs(int marks)

}goal+=k*score(i,j);//估計最高得分.

if(cnt<_min>

}} }

if(goal+marks<=ans)

if(goal==0)

if(cnt==0)

int _area=area(px,py),scr=score(px,py);

for(int i=1;i<=9;i++) }

return ;

} int main()

dfs(ans);

if(f)

else

return 0;

}

NOIP 2009 靶形數獨題解

題目的一些資訊就不給了,點鏈結吧。解題思路 我總結為乙個要點,乙個優化 要點 搜尋順序不能 for i 1 i 9 i for j 1 j 9 j 這樣時間複雜度過不去。如何搜尋?當做填數字一樣,每乙個格仔列舉陣列,從上到下,從左到右填過去。優化 這真的是欺負我這種沒有玩過數獨的人。從已經填數字多的...

noip2009靶形數獨題解

靶形數獨是乙個經典的np完全問題,沒有多項式演算法,顯然需要搜尋,遞迴回溯會優於列舉。然而此題資料範圍大,如果樸素搜尋顯然肯定tle,於是我們就需要一些優化。1.在搜尋中,每次我們都需要查詢當前格仔的可填數字,如果用二進位制數集儲存的話,可以大大減少執行時間。對於乙個格仔 x,y 可選數字為x行 y...

NOIP2009 靶形數獨

爆搜沒什麼好說的。剪枝思路 一開始將每個點可能取的值的數量統計出,排序,從小到大搜 然後貪心可行性 就是剩下的地方都填9,得分10 不過在vj上測85。日。加了卡時,2e7次之內跳出,總算過了。include include include include include include inclu...