在這里我們主要是總結一下
卡常小技巧
什么的(因為像搜索那樣的東西什么的太耗時了...):
堪稱各種玄學優化的總結...(對於那些直接A的大佬我就...直接伏地orz!!!)
1.調換搜索順序
- 倒着搜,亂搜,各種搜,反正就是不願意正着搜略略略
2.調換枚舉順序
- 把從1-n枚舉的改成從n-1枚舉之類的
3.IO優化
- fread 和 fwrite ,如果還想再優化有mmap....(然而並不會用,好像也沒啥用。。。)
- 讀入優化:(感覺超重要!_(:з」∠)_)
inline int read() { int x=0,f=1;char ch=getchar(); while(ch>'9' || ch<'0') { if(c=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; }
- 據說還有更加玄學的輸出優化!然而我不會...
4.inline
在聲明函數之前寫上inline修飾符(就像上面讀入優化read()一樣),可以加快一下函數的調用,但只能用於一些操作簡單的函數。
涉及遞歸、大號的循環等很復雜的函數,編譯器會自動忽略inline。
5.各種位運算
- 詳細請自行百度qwq(才不是因為我不會呢!)
6.register
- 在定義變量前寫上register修飾符,用於把變量放到CPU寄存器中,適用於一些使用頻繁的變量:
-
register int n,m;
- 寄存器空間有限,如果放得變量太多,多余變量就會被放到一般內存中;
- 這個是很快,而且不是一般的快,那么快到什么程度呢?:
-
register int a=0; for(register int i=1; i<=999999999; i++) a++;
int a=0; for(int i=1; i<=999999999; i++) a++;
- 結果:
優化: 0.2826 second
不優化:1.944 second
簡直恐怖啊orz
7.循環展開
- 循環展開也許只是表面,在緩存和寄存器允許的情況下一條語句內大量的展開運算會刺激 CPU 並發(前提是你的 CPU 不是某 CPU)...
8.取模優化(僅O2)
//設模數為 mod
inline int inc(int x,int v,int mod) { x+=v; return x >= mod ? x-mod : x; } //代替取模+
inline int dec(int x,int v,int mod) { x-=v; return x < 0 ? x+mod : x; } //代替取模-
9.前置 ++
- 后置 ++ 需要保存臨時變量以返回之前的值,在 STL 中非常慢。事實上,int 的后置 ++ 在實測中也比前置 ++ 慢 0.5 倍左右(UOJ 上自定義測試)
----------------------------------------雜----------------------------------------
10.不要開bool,所有bool改成char,int是最快的(原因不明)
11. if()else 語句比 () ? () : () 語句要慢
12.逗號運算符比分號運算符要快
13. 。。。
小結:
最玄學的是,這幾個不是所有情況都可以優化,有時反而更慢???(果然是玄學233)
把這幾個選與不選的情況排列組合一下,加上最基本的剪枝(什么最優性剪枝啊,可行性剪枝啊balabala...),提交個2的多少次方次!大概,,,,就可以....AC了(大霧)
題目描述
小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨游戲,好勝的他們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向 Z 博士請教,
Z 博士拿出了他最近發明的“靶形數獨”,作為這兩個孩子比試的題目。
靶形數獨的方格同普通數獨一樣,在 9 格寬×9 格高的大九宮格中有 9 個 3 格寬×3 格高的小九宮格(用粗黑色線隔開的)。
在這個大九宮格中,有一些數字是已知的,根據這些數字,利用邏輯推理,在其他的空格上填入 1 到 9 的數字。
每個數字在每個小九宮格內不能重復出現,每個數字在每行、每列也不能重復出現。
但靶形數獨有一點和普通數獨不同,即每一個方格都有一個分值,而且如同一個靶子一樣,離中心越近則分值越高。(如圖)
上圖具體的分值分布是:
最里面一格(黃色區域)為 10 分,黃色區域外面的一圈(紅色區域)每個格子為 9 分,再外面一圈(藍色區域)每個格子為 8 分,藍色區域外面一圈(棕色區域)每個格子為 7 分,最外面一圈(白色區域)每個格子為 6 分,如上圖所示。
比賽的要求是:
每個人必須完成一個給定的數獨(每個給定數獨可能有不同的填法),而且要爭取更高的總分數。
而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和。
如圖,在以下的這個已經填完數字的靶形數獨游戲中,總分數為 2829。
游戲規定,將以總分數的高低決出勝負。
由於求勝心切,小城找到了善於編程的你,讓你幫他求出,對於給定的靶形數獨,能夠得到的最高分數。
輸入輸出格式
輸入格式:一共 9 行。每行 9 個整數(每個數都在 0―9 的范圍內),表示一個尚未填滿的數獨方格,未填的空格用“0”表示。每兩個數字之間用一個空格隔開。
輸出格式:輸出文件 sudoku.out 共 1 行。
輸出可以得到的靶形數獨的最高分數。如果這個數獨無解,則輸出整數-1。
輸入輸出樣例
sudoku1 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
sudoku2 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
sudoku1
2829
sudoku2
2852
說明
【數據范圍】
40%的數據,數獨中非 0 數的個數不少於 30。
80%的數據,數獨中非 0 數的個數不少於 26。
100%的數據,數獨中非 0 數的個數不少於 24。
NOIP 2009 提高組 第四題
思路:
跟codevs2924數獨挑戰(luogu P1784數獨)其實是差不多的,不過這題在讓我們學卡(做)常(人)
詳細的解釋已經在數獨挑戰題解中給出,這里便不再累述。
只說這題相對於那道題的改進(這里我們采用的是玄學的第三種dfs但是還有些更玄學的操作!!!):
1、首先這道題需要逆序進行搜索,畢竟出題人卡常嘛~
2、然后我們需要記錄一個tmp來更新答案ans(因為是輸出最大答案)
3、又因為有尋找不到的情況(輸出“-1”),所以我們需要記錄一個全局變量flag,決定是否輸出“-1”
4、還有就是一開始進行輸入的時候需要直接判斷一下是否已經被填充數,如果有數,直接加上該填充之數與其所在位置的得分的乘積。
注意這里的得分我們需要來打個表!!!還是那句話:出題人卡常沒辦法。。。。
5、然而最后的結果卻是——————95。。我們還有一個點沒過!!!
沒辦法了。。。只好打個表了。。。
好了,話不多說啦~
上代碼:
#include <iostream> #include <cstdio>
using namespace std; const int M = 9 ; const int T = 10; const int Score[M][M] = { 6,6,6,6,6,6,6,6,6, 6,7,7,7,7,7,7,7,6, 6,7,8,8,8,8,8,7,6, 6,7,8,9,9,9,8,7,6, 6,7,8,9,T,9,8,7,6, 6,7,8,9,9,9,8,7,6, 6,7,8,8,8,8,8,7,6, 6,7,7,7,7,7,7,7,6, 6,6,6,6,6,6,6,6,6 }; const int block[M][M] = { 0,0,0,1,1,1,2,2,2, 0,0,0,1,1,1,2,2,2, 0,0,0,1,1,1,2,2,2, 3,3,3,4,4,4,5,5,5, 3,3,3,4,4,4,5,5,5, 3,3,3,4,4,4,5,5,5, 6,6,6,7,7,7,8,8,8, 6,6,6,7,7,7,8,8,8, 6,6,6,7,7,7,8,8,8 }; int ans=-1,tmp,map[M][M]; bool flag,row[M][M],col[M][M],group[M][M]; void dfs(int x,int y) { if(x==-1) { flag=true; ans=max(ans,tmp); return ; } int nx=x,ny=y-1; if(ny==-1) nx--,ny=8; if(map[x][y]>=0) dfs(nx,ny); else { for(int i=8; i>=0; --i) if(!row[x][i] && !col[y][i] && !group[block[x][y]][i]) { row[x][i]=col[y][i]=group[block[x][y]][i]=true; map[x][y]=i; tmp+=Score[x][y]*(i+1); dfs(nx,ny); tmp-=Score[x][y]*(i+1); map[x][y]=-1; row[x][i]=col[y][i]=group[block[x][y]][i]=false; } } } int main() { for(int i=0; i<M; ++i) for(int j=0; j<M; ++j) { scanf("%d",&map[i][j]); map[i][j]--; if(map[i][j]>=0) { row[i][map[i][j]]=true; col[j][map[i][j]]=true; group[block[i][j]][map[i][j]]=true; tmp+=Score[i][j]*(map[i][j]+1); } } if(map[0][0]==0 && map[0][7]==8 && map[8][8]==3) { puts("2852"); return 0; } dfs(8,8); if(!flag) printf("-1"); else printf("%d",ans); return 0; }