codevs 數獨系列 題解報告
4966 簡單數獨 4491 驗證數獨 2207 驗證數獨
2924 數獨挑戰 1174 靶形數獨
一共5道題目,全都和數獨有關:
4966 簡單數獨
時間限制: 1 s
空間限制: 1000 KB
題目等級 : 黃金 Gold
題解
題目描述 Description
某一天,小強忽然迷上了數獨,他想從最簡單的數獨做起,即4*4的數獨,然而他仍然做不出來,所以想請你幫幫他。4*4即每個數字在每一行、每一列和每一區只能出現一次。
輸入描述 Input Description
4行4列。
每個數字用空格隔開。
0代表要填的數.
輸出描述 Output Description
輸出答案。
排成4行4列。
每個數字用空格隔開.
樣例輸入 Sample Input
0 0 4 0
2 0 0 0
1 0 0 0
0 0 3 0
樣例輸出 Sample Output
3 1 4 2
2 4 1 3
1 3 2 4
4 2 3 1
資料範圍及提示 Data Size & Hint
保證有且只有一個解
首先T1;
簡單數獨,
一個4*4的
簡單的DFS列舉即可
h[][]為行的判重,l為列
s為小區間
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#include<ctime>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
#define searchnext(x,y) y==4? dfs(x+1,1):dfs(x,y+1)
using namespace std;
int n=4,m,a[10][10],score=0,ans=-1,b[10][10];
bool h[10][10],l[10][10],g[10][10];
inline int get_num()
{
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
bool add(int x,int y ,int k)
{
if(h[x][k])return 0;
if(l[y][k])return 0;
int ll=(x-1)/2*2+(y-1)/2+1;
if(g[ll][k])return 0;
h[x][k]=1;
l[y][k]=1;
g[ll][k]=1;
b[x][y]=k;
return 1;
}
void del(int x,int y,int k)
{
h[x][k]=0;
l[y][k]=0;
g[(x-1)/2*2+(y-1)/2+1][k]=0;
b[x][y]=0;
}
bool vv=0;
void dfs(int x,int y)
{
if(vv)return;
//if(clock()>1000)return;
if(x==5&&y==1)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cout<<b[i][j]<< " ";
}cout<<endl;
}
vv=1;
return;
}
if(b[x][y])
{
searchnext(x,y);
}else
{
for(int i=1;i<=4;i++)
{
if(add(x,y,i))
{
searchnext(x,y);
del(x,y,i);
}
}
}
}
int main()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
if(a[i][j])
{
add(i,j,a[i][j]);
}
}
}
dfs(1,1);
}
然後T2
4491 驗證數獨
時間限制: 1 s
空間限制: 128000 KB
題目等級 : 青銅 Bronze
題解
題目描述 Description
具體規則如下:
每一行都用到1、2、3、4、5、6、7、8、9,位置不限;
每一列都用到1、2、3、4、5、6、7、8、9,位置不限;
每3×3的格子(共九個這樣的格子)都用到1、2、3、4、5、6、7、8、9,位置不限。
遊戲的過程就是用1、2、3、4、5、6、7、8、9填充空白,並要求滿足每行、每列、每個九宮格都用到1、2、3、4、5、6、7、8、9。
如下是一個正確的數獨:
5 8 1 4 9 3 7 6 2
9 6 3 7 1 2 5 8 4
2 7 4 8 6 5 9 3 1
1 2 9 5 4 6 3 7 8
4 3 6 1 8 7 2 9 5
7 5 8 3 2 9 1 4 6
8 9 2 6 7 1 4 5 3
6 1 5 9 3 4 8 2 7
3 4 7 2 5 8 6 1 9
輸入描述 Input Description
輸入n個數獨,你來驗證它是否違反規則。
第一行為數獨個數,第二行開始為第一個數獨,之後為第二個,至第n個。
注意!每個數獨之間有一個回車隔開!
輸出描述 Output Description
若正確則輸出”Right”若不正確則輸出”Wrong”,輸出一個換一行。
樣例輸入 Sample Input
2
5 8 1 4 9 3 7 6 2
9 6 3 7 1 2 5 8 4
2 7 4 8 6 5 9 3 1
1 2 9 5 4 6 3 7 8
4 3 6 1 8 7 2 9 5
7 5 8 3 2 9 1 4 6
8 9 2 6 7 1 4 5 3
6 1 5 9 3 4 8 2 7
3 4 7 2 5 8 6 1 9
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9 1
3 4 5 6 7 8 9 1 2
4 5 6 7 8 9 1 2 3
5 6 7 8 9 1 2 3 4
6 7 8 9 1 2 3 4 5
7 8 9 1 2 3 4 5 6
8 9 1 2 3 4 5 6 7
9 1 2 3 4 5 6 7 8
樣例輸出 Sample Output
Right
Wrong
資料範圍及提示 Data Size & Hint
1≤n≤20(輸入的數獨個數)。
不論輸入的數獨是錯誤的還是正確的,資料都保證每個數在1-9之間,即只會出現因為有相同的數而導致違反規則,而不會因為數字超出了1-9的範圍而違反規則。
這個題不讓解數獨,只要判斷是否正確,也就是同一行同一列,同意區間,有沒有相同 的就好,
和上一題一樣,設3個判重陣列,一一列舉即可;;
程式碼::
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#include<ctime>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
#define searchnext(x,y) y==9? dfs(x+1,1):dfs(x,y+1)
using namespace std;
int n=9,m,a[10][10],score=0,ans=-1,b[10][10];
bool h[10][10],l[10][10],g[10][10];
inline int get_num()
{
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
bool add(int x,int y ,int k)
{
if(h[x][k])return 0;
if(l[y][k])return 0;
int ll=(x-1)/3*3+(y-1)/3+1;
if(g[ll][k])return 0;
h[x][k]=1;
l[y][k]=1;
g[ll][k]=1;
b[x][y]=k;
return 1;
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(h,0,sizeof(h));
memset(l,0,sizeof(l));
memset(g,0,sizeof(g));
bool vv=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
if(a[i][j])
{
if(!add(i,j,a[i][j]))
{
vv=1;
}
}
}
}
if(!vv)
cout<<"Right\n";
else
cout<<"Wrong\n";
}
}
T3‘
2924 數獨挑戰
時間限制: 1 s
空間限制: 1000 KB
題目等級 : 鑽石 Diamond
題解
題目描述 Description
“芬蘭數學家因卡拉,花費3個月時間設計出了世界上迄今難度最大的數獨遊戲,而且它只有一個答案。因卡拉說只有思考能力最快、頭腦最聰明的人才能破解這個遊戲。”這是英國《每日郵報》2012年6月30日的一篇報道。這個號稱“世界最難數獨”的“超級遊戲”,卻被揚州一位69歲的農民花三天時間解了出來。
看到這個新聞後,我激動不已,證明我們OI的實力的機會來了,我們雖然不是思考能力最快、頭腦最聰明的人,但是我們可以保證在1s之內解題。
好了廢話不多說了……
數獨是一種填數字遊戲,英文名叫Sudoku,起源於瑞士,上世紀70年代由美國一家數學邏輯遊戲雜誌首先發表,名為Number Place,後在日本流行,1984年將Sudoku命名為數獨,即“獨立的數字”的省略,解釋為每個方格都填上一個個位數。2004年,曾任中國香港高等法院法官的高樂德(Wayne Gould)把這款遊戲帶到英國,成為英國流行的數學智力拼圖遊戲。
玩家需要根據9×9盤面上的已知數字,推理出所有剩餘位置(資料表示為數字0)的數字,並滿足每一行、每一列、每一個粗線宮內的數字均含1-9,不重複。
現在給你一個數獨,請你解答出來。每個數獨保證有解且只有一個。
輸入描述 Input Description
9行9列。
每個數字用空格隔開。0代表要填的數
行末沒有空格,末尾沒有回車。
輸出描述 Output Description
輸出答案。
排成9行9列。
行末沒有空格,結尾可以有回車。
樣例輸入 Sample Input
2 0 0 0 1 0 8 9 0
0 0 7 0 0 0 0 0 0
0 0 0 9 0 0 0 0 7
0 6 0 0 0 1 3 0 0
0 9 0 7 3 4 0 8 0
0 0 3 6 0 0 0 5 0
6 0 0 0 0 2 0 0 0
0 0 0 0 0 0 1 0 0
0 5 9 0 8 0 0 0 3
樣例輸出 Sample Output
2 4 5 3 1 7 8 9 6
9 1 7 2 6 8 5 3 4
3 8 6 9 4 5 2 1 7
4 6 2 8 5 1 3 7 9
5 9 1 7 3 4 6 8 2
8 7 3 6 2 9 4 5 1
6 3 8 1 7 2 9 4 5
7 2 4 5 9 3 1 6 8
1 5 9 4 8 6 7 2 3
資料範圍及提示 Data Size & Hint
保證有解,每個數獨都由http://oubk.com數獨網提供。
其中資料hard1.in為芬蘭數學家提供。
這個題就是T1的升級版
求一個9*9的數獨
其實程式一樣,只是某些數變了而已;;
程式碼:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#include<ctime>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
#define searchnext(x,y) y==9? dfs(x+1,1):dfs(x,y+1)
using namespace std;
int n=9,m,a[10][10],score=0,ans=-1,b[10][10];
bool h[10][10],l[10][10],g[10][10];
inline int get_num()
{
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
bool add(int x,int y ,int k)
{
if(h[x][k])return 0;
if(l[y][k])return 0;
int ll=(x-1)/3*3+(y-1)/3+1;
if(g[ll][k])return 0;
h[x][k]=1;
l[y][k]=1;
g[ll][k]=1;
b[x][y]=k;
return 1;
}
void del(int x,int y,int k)
{
h[x][k]=0;
l[y][k]=0;
g[(x-1)/3*3+(y-1)/3+1][k]=0;
b[x][y]=0;
}
bool vv=0;
void dfs(int x,int y)
{
if(vv)return;
//if(clock()>1000)return;
if(x==10&&y==1)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cout<<b[i][j]<< " ";
}cout<<endl;
}
vv=1;
return;
}
if(b[x][y])
{
searchnext(x,y);
}else
{
for(int i=1;i<=9;i++)
{
if(add(x,y,i))
{
searchnext(x,y);
del(x,y,i);
}
}
}
}
int main()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
if(a[i][j])
{
add(i,j,a[i][j]);
}
}
}
dfs(1,1);
}
T4
1174 靶形數獨 2009年NOIP全國聯賽提高組
時間限制: 4 s
空間限制: 128000 KB
題目等級 : 鑽石 Diamond
題解
題目描述 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。
這個題是T3的升級版,對於每個位置上的數給了價值,
做法就是dfs出數獨的每一種情況,之後計算得分,取最大值;
但是會TLE;
codevs加上卡時之後80分。
但是,將輸入倒過來就能AC了;
看來是出題人故意卡的順序讀入;
程式碼::
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#include<ctime>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
#define searchnext(x,y) y==9? dfs(x+1,1):dfs(x,y+1)
using namespace std;
int n=9,m,a[10][10],score=0,ans=-1,b[10][10];
bool h[10][10],l[10][10],g[10][10];
inline int get_num()
{
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
int getscore(int x,int y,int k)
{
if(x==y&&x==5)
{
return k*10;
}
if(x==1||x==n||y==1||y==n)return 6*k;
if(x==2||x==8||y==2||y==8)return 7*k;
if(x==3||x==7||y==3||y==7)return 8*k;
if(x==4||x==6||y==4||y==6)return 9*k;
}
bool add(int x,int y ,int k)
{
if(h[x][k])return 0;
if(l[y][k])return 0;
int ll=(x-1)/3*3+(y-1)/3+1;
if(g[ll][k])return 0;
h[x][k]=1;
l[y][k]=1;
g[ll][k]=1;
b[x][y]=k;
score+=getscore(x,y,k);
return 1;
}
void del(int x,int y,int k)
{
h[x][k]=0;
l[y][k]=0;
g[(x-1)/3*3+(y-1)/3+1][k]=0;
b[x][y]=0;
}
void dfs(int x,int y)
{
//if(clock()>1000)return;
if(x==10&&y==1)
{
ans=max(ans,score);
return;
}
if(b[x][y])
{
searchnext(x,y);
}else
{
for(int i=1;i<=9;i++)
{
int t=score;
if(add(x,y,i))
{
searchnext(x,y);
del(x,y,i);
score=t;
}
}
}
}
int main()
{
for(int i=n;i>=1;i--)
{
for(int j=n;j>=1;j--)
{
cin>>a[i][j];
if(a[i][j])
{
add(i,j,a[i][j]);
}
}
}
dfs(1,1);
cout<<ans;
}
嗚啦啦啦啦