P1074 靶形數獨

2022-05-05 16:18:11 字數 4183 閱讀 5301

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

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

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

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

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

輸入格式:

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

輸出格式:

輸出共 111 行。輸出可以得到的靶形數獨的最高分數。如果這個數獨無解,則輸出整數 −1-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%的資料,數獨中非 000 數的個數不少於 30 3030 。

80%的資料,數獨中非 000 數的個數不少於 262626 。

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

noip 2009 提高組 第四題

大暴搜啊

普通做法判斷行,列,宮,跑的賊慢。

舞蹈鏈可做……然而不會啊

= 打成 == 調了乙個小時。。。碼力不足qwq

我可能要練一練暴搜和模擬了qwq

#include #include 

#include

#include

#include

using

namespace

std;

const

int f[10][10] =,,,

,,,,

,,};int m[10][10], toth[10], totl[10], ans = -1

;bool hang[10][10], lie[10][10], area[10][10

];int slv(int i, int

j) void dfs(int x, int y, int

stp)

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

}int

main()

}int maxx = -1, maxy = -1

, sx, sy;

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

if (maxx < toth[i] && toth[i] < 9) maxx = toth[i], sx =i;

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

if (maxy < totl[i] && !m[sx][i]) maxy = totl[i], sy =i;

dfs(sx, sy, sp);

printf(

"%d\n

", ans);

return0;

}

跑了3000+ms

目前最快的正解跑了100+ms

大佬的**

#includeusing

namespace

std;

struct nodew[128

];short can_get[128

];inline

bool cmp(const node &a,const node &b)

short zt[16][4

];short done[16][16],be[16][16

];short fz[16][16]=,,,

,,,,

,,};short qz[16][16

];short nex[1024],pre[1024

];int

bes,now,bs;

inline

void dfs(register int

p)

if(done[w[p].x][w[p].y])

if((can_get[p]<<3)+can_get[p]+now<=bes) return

; ++bs;

if(bs>=1900000) return

; register

int x=w[p].x,y=w[p].y,bel=be[x][y],can_use=zt[x][0]&zt[y][1]&zt[bel][2

],t,z;

if(fz[x][y]<=6

) }

else

}}int

main()

}for(register int i=0;i<9;i++)

for(register int j=0;j<9;j++)

for(register int i=0;i<9;i++)

for(register int l=0;l<9;l++)

}be[i][j]=(i/3)*3+j/3

; }

}sort(w,w+81

,cmp);

for(register int i=80;i>=0;i--)

for(register int i=1;i

<<9);i++)

dfs(0);

if(bes==0) puts("-1"

);

else printf("

%d\n

",bes);

return0;

}

emmmm……用了位運算……

基本做法差不多,但是多了幾個剪枝。

這一句怎麼看都很玄學

if(bs>=1900000) return;
至今仍搞不懂原理

剪枝……真玄學啊qwq

P1074 靶形數獨

p1074 靶形數獨 比賽的要求是 每個人必須完成乙個給定的數獨 每個給定數獨可能有不同的填法 而且要爭取更高的總分數。而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和 輸入格式 一共 99 行。每行99個整數 每個數都在 0 9的範圍內 表示乙個尚未填滿的數獨方格,未填...

P1074 靶形數獨

題意 給你乙個未完成的數獨,每個位置上的價值等於數字乘上位置的價值 類似於打靶子 要點 1.巧妙利用打表便於搜尋與判斷 2.貪心思想大量減少搜尋的分支 每行 列 選0的個數少的填,減少了分支 不加此剪枝tle一片。1 剛開始別忘了加上初始的數的value 2 打表注意 0 0 都是 0,因為打錯表找...

P1074 靶形數獨 題解

原題傳送門 不愧是 2009 noip tg t4 連續打了4天的 吸了口氧才通過。前置知識 對於一道數獨題,我們可以先預處理出每一行0的個數,然後從個數最少的行開始做,這樣可以節省大量的時間 因為這些格仔可以填的數字少 對於本題,我一開始的思路是 仿照前置知識預處理,分數進行打表,存在 poi n...