傳送門
小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨遊戲,好勝的他們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向 z 博士請教,z 博士拿出了他最近發明的"靶形數獨",作為這兩個孩子比試的題目。
靶形數獨的方格同普通數獨一樣,在 \(9\) 格寬×\(9\) 格高的大九宮格中有\(9\) 個 \(3\) 格寬×\(3\) 格高的小九宮格(用粗黑色線隔開的)。在這個大九宮格中,有一些數字是已知的,根據這些數字,利用邏輯推理,在其他的空格上填入 \(1\) 到 \(9\)的數字。每個數字在每個小九宮格內不能重複出現,每個數字在每行、每列也不能重複出現。但靶形數獨有一點和普通數獨不同,即每乙個方格都有乙個分值,而且如同乙個靶子一樣,離中心越近則分值越高。(如圖)
上圖具體的分值分布是:最裡面一格(黃色區域)為 \(10\) 分,黃色區域外面的一圈(紅色區域)每個格仔為\(9\)分,再外面一圈(藍色區域)每個格仔為$ 8$ 分,藍色區域外面一圈(棕色區域)每個格仔為\(7\) 分,最外面一圈(白色區域)每個格仔為\(6\)分,如上圖所示。比賽的要求是:每個人必須完成乙個給定的數獨(每個給定數獨可能有不同的填法),而且要爭取更高的總分數。而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和。
總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和。如圖,在以下的這個已經填完數字的靶形數獨遊戲中,總分數為 2829。遊戲規定,將以總分數的高低決出勝負。
由於求勝心切,小城找到了善於程式設計的你,讓你幫他求出,對於給定的靶形數獨,能夠得到的最高分數。
一共 \(9\) 行。每行$ 9 $個整數(每個數都在 \(0-9\) 的範圍內),表示乙個尚未填滿的數獨方格,未填的空格用"\(0\)"表示。每兩個數字之間用乙個空格隔開。
輸出共 \(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
2829
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
2852
【資料範圍】
\(40\%\)的資料,數獨中非 \(0\) 數的個數不少於\(30\)。
\(80\%\)的資料,數獨中非 \(0\) 數的個數不少於\(26\)。
\(100\%\)的資料,數獨中非\(0\)數的個數不少於\(24\)。
noip 2009
提高組 第四題
這是一道很有趣的技巧性搜尋,看了下資料範圍和時限,好像暴搜有點危險,自己就加了乙個優化:
找空地少的一行開始搜。
啥意思呢,我們平常做數獨的時候,一般都是從填的數最少的那一行開始,如果程式我們用這個優化,會減掉好多枝。美滋滋。
然後就是一些細節問題了,比如上面所說的優化,還有分數的計算什麼的,在這些方面我踩了好多坑,debug
了很長時間。不過多踩點坑總是好的。
具體請見**,注釋個人認為比較詳盡。
另外,從主函式開始閱讀**是個好習慣,否則你可能會雲裡霧裡。
/*
* @author: crab-in-the-northeast
* @date: 2020-02-23 13:23:05
* @last modified by: crab-in-the-northeast
* @last modified time: 2020-02-23 16:03:12
*/#include #include #include #include const int maxn = 15;
int sudoku[maxn][maxn],score[maxn][maxn];//數獨和每個位置對應的分數
int first[85];
//這個first有點難理解,對first[i],i表示順序,i越小,掃到的點越靠前。
//而first[i]是乙個int值,用來存放第i個搜尋到的點在數獨中的位置,這裡所說的位置
//已經經過了對映,也就是將數獨中點的位置的二維對映到一維。
//對映方法很簡單,(x-1)*9+y
int ans;//存放答案
bool visc[maxn][maxn],visr[maxn][maxn],visg[maxn][maxn];
//標記每一行,每一列,每一宮的訪問情況。具體:
//比如visc[i][j]表示第i行中數j是否出現。
//根據英文來說,visc是列,visr是行,但是本程式中全都寫反了,也就懶得改了。
bool fnd;//標記有無解
inline int max(int a,int b)
struct row r[maxn];
bool cmp(row a,row b)
int cal()
void dfs(int step)
int x = first[step] / 9 + 1;
int y = first[step] % 9;
if(!y)
//一維對映到二維。
if(sudoku[x][y]) dfs(step + 1);
//如果sudoku[x][y]成立說明當前的數不是0,也就是當前位置是已知的數,不能更改。
//我們直接跳過去,搜尋下乙個就好、
else }}
}int main()
}r[i].ind = i;//這裡要記錄一下,因為一會要排序,行數會丟失。
r[i].zero = zero;//記錄當前行中0的數量
}std :: sort(r+1,r+10,cmp);//對行進行排序
for(int i = 1; i <= 9; i++)
}for(int i = 1,j = 10 - i; i <= 5; i++,j--)
for(int k = i; k <= j; k++)
score[i][k] = score [k][i] = score[k][j] = score[j][k] = i + 5;
//預處理score陣列,便於計算總分
dfs(1);//進行dfs
if(fnd) printf("%d\n",ans);
else printf("-1\n");
//輸出答案
return 0;//結束程式
}
ac 100
:r30975285
over.
Luogu P1074 靶形數獨
include using namespace std struct consult row 0 struct consult row 0 dic row 0 10 查詢第幾行有幾個0 int origin 10 10 輸入的數獨 bool row 10 10 column 10 10 box 10...
luogu P1074 靶形數獨
比較基礎的搜尋剪枝題。幾個優化就可以過了 用lowbit代替查詢可以填的數 用並集來維護什麼數不能填 優先考慮 最小可能性的位置 講道理我用堆維護還t了。然後就可以在 m n是數獨大小,m是可以填的種類數量 解決 實際測試中,遠遠不到這個上界 include using namespace std ...
luogu P1074 靶形數獨
小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨遊戲,好勝的他們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向 z 博士請教,z 博士拿出了他最近發明的 靶形數獨 作為這兩個孩子比試的題目。靶形數獨的方格同普通數獨一樣,在 99 格寬 99 格高的大九宮格中有 99...