遇事不決打暴力!—— 那些讓人感覺“這他媽也能過?”的暴力題集錦(不斷更新)
數獨 —— 九宮格
首先說一道大多數人應該都很熟悉的題——求解數獨。
簡單直接粗獷分析地話,這個題目有9 * 9 = 81個未知數,每個數有9種選擇,一共是8^81這種複雜度。如果再考慮每個塊裡面每個數只能出現一次,那可以簡化到(9!)^9。
但是實際上考慮到各種剪枝,這個題目寫裸的DFS,只要有解,就算是號稱“世界上最難的數獨”問題都能在1000ms之內求解。這個大多數玩家應該都有過體會。
旋轉的數獨
應該是在某場開火車看到的題,題意是有一個擴充套件到16*16的數獨,字符集是[0-9]+[A-F],其中4*4的16個小塊被獨立地順時針旋轉了若干次,給了你旋轉之後的九宮格局面,問最少多少次逆時針旋轉能夠將其還原。
該題目中每個小的九宮格都有可以被旋轉0-3次,那麼一共有4^16種可能。乍一看是絕對會TLE的,但是事實上同樣我們可以用一些小技巧來剪枝。其實這個演算法直接跑暴力還是很快的,但是我個人是寫了一些小的優化。
為了方便描述,把4*4的小塊編號
0 1 2 3
4 5 6 7
8 9 a b
c d e f
我是按照2, 5, 8, 7, a, d, 6, 9, 1,4, b, e, 0, 3, f c的順序來列舉的,畫一下圖的話就可以發現這個按順序列舉的話剪枝效果拔群。以及在列舉的過程中直接用bitset來維護每一行每一列是否0-f都有,效率也比較高
(不過無腦暴力+無腦check據說也是能過,我想多了)
撲克牌
這個題好像也是開火車遇到的,題意說給出K張撲克牌,最多52張。撲克牌牌面是1 2 3 4 5 6 7 8 9 T J Q K,每種最多四張。TJQK分別表示10,11,12,13。第一張牌可以隨意打出,之後打出的牌上的數字都要整除前面打出過的所有數字的和。
這個題完全無腦暴力可以知道複雜度是52!的,也就是枚舉出牌順序。
題目在現場賽前幾個小時基本沒有隊做,大概是覺得複雜度不對吧。我看完題就想著這個肯定能爆搜,得想辦法搞他孃的一炮。於是想到了倒著列舉,從最後一張牌開始列舉。最後所有數字的和是確定的,最後一張牌上的數字肯定要是總和的因子,這樣就剪了大量的枝,然後一步一步推下去。
一開始沒有看到每個牌最多四張,還怕暴力列舉會被卡,然後就把列舉順序random_shuffle了一下,按照一個隨機的順序來列舉。事實證明的確比純暴力快了很多。。但是並沒有什麼用。
Black and White, 2014 ACM/ICPC Beijing Regional
說實話在區域賽題目看到這個還是很震驚的,,印象中北京的題一向靠譜,連續去了兩年正準備去第三年。
題目給了一個N*M的國際象棋棋盤,要求用K種顏色染色,滿足相鄰兩格顏色不同以及第 i 種顏色正好使用了ai次。題目保證a1 + a2 + ... + ak = N*M。其中N, M <= 5。
看到這個題我跟隊友第一想法是能不能狀壓DP或者折半查詢。。想了想發現不太行,然後想能不能構造。想了半天構造,我靈機一動想到一個構造方法(假演算法)!看了看樣例好像都行得通,馬上開始寫了,心中暗暗竊喜。寫完交上去發現WA了,冥思苦想半天沒想到為什麼會錯。於是乎準備打暴力對拍,寫了個簡單的DFS,從左往右從上往下填,唯二的剪枝條件就是相鄰格子不同色 + 某個顏色剩下數量*2 > 剩下格子數+1 這麼簡單的條件。
暴力寫完了開始對拍,然後就驚了。發現不對勁啊,錯倒是沒找出來,倒是發現這暴力跑得飛快。。理論來說這個複雜度有點假了啊。。但是事實面前不得不服。。它就是能過。。有空還仔細研究一下。
階段性小結(題目還會持續更新)
總而言之就是驚了。可能我對這種暴力演算法的複雜度還不是很有概念,很多剪枝算不清楚。的確好多之前看來不可能能過的題暴力都跑得飛快。以後遇到這種類似的題目真的該好好考慮一下爆搜了。。。
剪枝大法好,勝利屬於暴力打表老司機。