codevs1174 靶形數獨 DLX

2022-08-18 03:24:13 字數 3157 閱讀 4100

題目描述 description

小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨遊戲,好勝的他

們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向z 博士請教,

z 博士拿出了他最近發明的「靶形數獨」,作為這兩個孩子比試的題目。

靶形數獨的方格同普通數獨一樣,在 9 格寬×9 格高的大九宮格中有9 個3 格寬×3 格

高的小九宮格(用粗黑色線隔開的)。在這個大九宮格中,有一些數字是已知的,根據這些

數字,利用邏輯推理,在其他的空格上填入1 到9 的數字。每個數字在每個小九宮格內不能

重複出現,每個數字在每行、每列也不能重複出現。但靶形數獨有一點和普通數獨不同,即

每乙個方格都有乙個分值,而且如同乙個靶子一樣,離中心越近則分值越高。

上圖具體的分值分布是:最裡面一格(黃色區域)為 10 分,黃色區域外面的一圈(紅

色區域)每個格仔為9 分,再外面一圈(藍色區域)每個格仔為8 分,藍色區域外面一圈(棕

色區域)每個格仔為7 分,最外面一圈(白色區域)每個格仔為6 分,如上圖所示。比賽的

要求是:每個人必須完成乙個給定的數獨(每個給定數獨可能有不同的填法),而且要爭取

更高的總分數。而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字

的乘積的總和。如圖,在以下的這個已經填完數字的靶形數獨遊戲中,總分數為2829。遊

戲規定,將以總分數的高低決出勝負。

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

夠得到的最高分數。

輸入描述 input description

一共 9 行。每行9 個整數(每個數都在0—9 的範圍內),表示乙個尚未填滿的數獨方

格,未填的空格用「0」表示。每兩個數字之間用乙個空格隔開。

輸出描述 output description

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

樣例輸入 sample input

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

樣例輸出 sample output

【輸入輸出樣例 1】

2829

【輸入輸出樣例 1】

2852

資料範圍及提示 data size & hint

【資料範圍】

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

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

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

貌似沒有別的辦法,只能搜尋所有的解,然後取權值最大的乙個。

這題我直接dfs只能過80%的資料。

數獨屬於精確覆蓋問題,dlx演算法是目前已知求解數獨的最有效的方法之一。

關於dlx請看這裡

我用的是劉汝佳《演算法競賽入門經典:訓練指南》上給出的**。

dlx演算法中,

行代表決策,因為要選一些行來覆蓋所有的列。每個決策用乙個三元組(r,c,v)表示,意思是將(r,c)格仔填上字母v,因此對於9*9的數獨一共有9*9*9=729行。

列代表任務,因為要讓每列恰好有乙個「1」,即每列都被覆蓋。一共有以下四種任務需要達成:

slot(a,b)表示第a行第b列要有數字

row(a,b)表示第a行要有數字b

col(a,b)表示第a列要有數字b

sub(a,b)表示第a個子方陣要有字母b

因此一共9*9*4=324列。

dlx矩陣中的「1」代表對應的決策達成了對應的任務。上面已經將決策寫成了三元組(r,c,v)的形式,它達成了四個任務:slot(r,c),row(r,v),col(c,v),sub(prc,k),其中prc表示第r行c列所在子方陣編號。不難算出一共有729*4=2916個結點。

#include#include#include#include#include#include#includeusing namespace std;

#define debug(x) cout<

for(int i = 0; i <= n; ++i)

r[n] = 0;l[0] = n;

sz = n+1;

memset(s,0,sizeof(s));

} void addrow(int r,const vector& cols)

r[sz - 1] = first; l[first] = sz - 1;

} void remove(int c)

} void restore(int c)

l[r[c]] = c;

r[l[c]] = c;

} int res;

bool dfs(int d)

int c = r[0];

rep(i,r,0)if(s[i] < s[c]) c = i;

remove(c);

rep(i,d,c)

restore(c);

return false;

} bool solve(vector& v)

return true;

} void getans()

res = max(res,tmp);

}}dlx;

void read() }}

int main()

//vectorans;

dlx.dfs(0);

printf("%d\n",dlx.res);

return 0;

}

codevs1174 靶形數獨

題目鏈結 題解 可以預處理出已經填數字比較密集的區域開始搜尋來減少後續決策數 include include include using namespace std const int n 9 int s,tot,ans int a 10 10 struct dataf 10 10 int fen ...

靶形數獨(codevs 1174)

2009年noip全國聯賽提高組 時間限制 4 s 空間限制 128000 kb 題目等級 鑽石 diamond 題解檢視執行結果 小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨遊戲,好勝的他 們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向z 博士請教,z 博士...

codevs1174 靶形數獨

從wyh大佬那裡蹭來了乙份dlx的題解,然後進行了一番深刻的理解,最後自己手打了一遍,感覺受益頗多,最主要的是這個 融合了很多卡常技巧2333333333 和普通的dfs不同,這份 從根進行剪枝,每一層都取方案數最小的位置進行搜尋,因而得到十分顯著的優化,原來乙個點4s的題,現在20個點總共用時加起...