靶形数独(信息学奥赛一本通-T1447)
【題目描述】
小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨游戲,好勝的他們想用數獨來一比高低。但普通的數獨對他們來說都過于簡單了,于是他們向Z 博士請教,Z 博士拿出了他最近發明的“靶形數獨”,作為這兩個孩子比試的題目。
靶形數獨的方格同普通數獨一樣,在 9 格寬×9 格高的大九宮格中有9 個3 格寬×3 格高的小九宮格(用粗黑色線隔開的)。在這個大九宮格中,有一些數字是已知的,根據這些數字,利用邏輯推理,在其他的空格上填入1 到9 的數字。每個數字在每個小九宮格內不能重復出現,每個數字在每行、每列也不能重復出現。但靶形數獨有一點和普通數獨不同,即每一個方格都有一個分值,而且如同一個靶子一樣,離中心越近則分值越高。(如圖)
上圖具體的分值分布是:最里面一格(黃色區域)為 10 分,黃色區域外面的一圈(紅色區域)每個格子為9 分,再外面一圈(藍色區域)每個格子為8 分,藍色區域外面一圈(棕色區域)每個格子為7 分,最外面一圈(白色區域)每個格子為6 分,如上圖所示。比賽的要求是:每個人必須完成一個給定的數獨(每個給定數獨可能有不同的填法),而且要爭取更高的總分數。而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和。如圖,在以下的這個已經填完數字的靶形數獨游戲中,總分數為2829。游戲規定,將以總分數的高低決出勝負。
由于求勝心切,小城找到了善于編程的你,讓你幫他求出,對于給定的靶形數獨,能夠得到的最高分數。
【輸入】
一共 9 行。每行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
樣例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
【源程序】
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<utility> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #include<bitset> #define EPS 1e-9 #define PI acos(-1.0) #define INF 0x3f3f3f3f #define LL long long const int MOD = 1E9+7; const int N = 1000+5; const int dx[] = {-1,1,0,0,-1,-1,1,1}; const int dy[] = {0,0,-1,1,-1,1,-1,1}; using namespace std; int g[N][N]; int grade[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 area[10][10] { //宮{0,0,0,0,0,0,0,0,0,0},{0,1,1,1,2,2,2,3,3,3},{0,1,1,1,2,2,2,3,3,3},{0,1,1,1,2,2,2,3,3,3},{0,4,4,4,5,5,5,6,6,6},{0,4,4,4,5,5,5,6,6,6},{0,4,4,4,5,5,5,6,6,6},{0,7,7,7,8,8,8,9,9,9},{0,7,7,7,8,8,8,9,9,9},{0,7,7,7,8,8,8,9,9,9}, }; struct Node {int x;int y; } point[N*10]; int vis_x[N][N],vis_y[N][N],vis_g[N][N]; int vis[N*10]; int n,sum; void dfs(int k) {if(k>n) { //當確定的數字個數大于未填入的數字總數時int cnt=0;for(int i=1; i<=9; i++) //記錄分值for(int j=1; j<=9; j++)cnt+=g[i][j]*grade[i][j];sum=max(sum,cnt);//取最大分值return;}int w=INF,temp;for(int i=1; i<=n; i++){ //確定搜索的起點if(!vis[i]) {int ww=0;for(int j=1; j<=9; j++)if( !vis_x[point[i].x][j] && !vis_y[point[i].y][j] && !vis_g[area[point[i].x][point[i].y]][j] )if(++ww==w)break;if(ww<w) {w=ww;temp=i;}}}vis[temp]=1;int x=point[temp].x;int y=point[temp].y;for(int i=1; i<=9; i++){ //枚舉每一層可能的狀態if( !vis_x[x][i] && !vis_y[y][i] && !vis_g[area[x][y]][i] ) { //如果當前數字在整個圖的橫向縱向小區域內未出現過g[x][y]=i;vis_x[x][i]=1;vis_y[y][i]=1;vis_g[area[x][y]][i]=1;dfs(k+1);vis_x[x][i]=0;vis_y[y][i]=0;vis_g[area[x][y]][i]=0;}}vis[temp]=0; } int main() {for(int i=1; i<=9; i++){for(int j=1; j<=9; j++) {scanf("%d",&g[i][j]);if(g[i][j]) {vis_x[i][g[i][j]]=1;//標記行vis_y[j][g[i][j]]=1;//標記列vis_g[area[i][j]][g[i][j]]=1;//標記圖}else { //如果當前點未填入數字/*記錄未填入數字*/n++;point[n].x=i;point[n].y=j;}}}sum=-1;dfs(1);cout<<sum<<endl;return 0; }?
總結
以上是生活随笔為你收集整理的靶形数独(信息学奥赛一本通-T1447)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 回文字符串(51Nod-1092)
- 下一篇: 理论基础 —— 树 —— 树的存储结构