題目
下面是乙個沒有數字,只有大小關係(沒錯!那些尖角都是「大於」符號!)的數獨:
除了大小關係外(注意相鄰格仔不能相同),還需要滿足通常的數獨規則:
l 每個格仔都是1~9 的數字
l 每行都是1~9的排列
l 每列都是1~9的排列
l 每個3*3的子矩陣(上圖中用粗線隔開,一共有3*3個這樣的子矩陣)都是1~9的排列
為了美觀,每個3*3子矩陣的所有12對相鄰格仔的大小關係都將給出。
這道題,我們可以注意到有樸素數獨的限制,例如每行都是1~9的排列
, 每列都是1~9的排列,但光有這個,搜尋還是很慢。
那些大於小於號,假設我們現在要確定9要放**,那麼畫出來的圖,對應9的位置,所有符號都是它指向外面的(就是它周圍的都是他指向外面的大於號),這簡直是9在大吼著:「我在這裡…」…於是我就順從了..
對於這個發現,我們可以從大到小列舉先放哪些數,放完9個位置後再放其他的,若存在a<b,則b連a一條邊,並將a入度+1。由於我們每次放的都是現存最大的數,那麼我們按小九宮格為單位,每個九宮格裡找到入度為0的位置,將數填進去,然後消除該位置對周圍位置的影響(類似拓撲排序,將它連出去的位置入度-1)。
加上這個優化,我們就可以飛快的跑過了….(說實話,剛提交**,連running都沒有看到..)
好了,我們來討論一下為甚麼這個剪枝這麼強力?
由於保證存在唯一解,對於相同決策,即同乙個數(指乙個小九宮格內)能填的位置(入度為0)的地方不會超過5,而當你選擇了乙個位置填入的時候,說明你周圍的位置都是先前不可能決策到的(這個可以證明前者),而當前存在多個決策時,則說明以後的決策會少那麼多(我們可以想著乙個正向決策即由大取到小,乙個反向決策即由小取到大)【而且加上數獨的限制,均攤相同決策不超過3個】均攤下來,若要跑得最慢的話,最大決策層在中間,只會有3個相同決策,其餘兩端決策數會依次遞減,均攤69
(我估計的,這也可以接受)而實際上非常小,通常由於唯一解,第一次就會直接搜到答案。
貼**
#include
#include
#include
#define n 10
using namespace std;
intin[82],g[82],a[1000][2],d[82],help[n],b[n];
bool bzh[9][9],bzz[9][9];
void ins(int x,int y)
void did1(int x)
x++;
}}void did2(int x)
}void init()
}int did(int x)
bool jian(int x,int y)
void change(int x,int y)
void changeback(int x,int y)
bool dfs(int x,int y)
if (!y)return
1; s=help[x];
++x;
for (int i=1;i<=9;i++)
if (!d[s+b[i]]&&jian(y,s+b[i])&&!in[s+b[i]])
return0;}
void work()
void write()
}int main()
GDOI2016模擬8 21新Nim遊戲
題目 傳統的nim遊戲是這樣的 有一些火柴堆,每堆都有若干根火柴 不同堆的火柴數量可以不同 兩個遊戲者輪流操作,每次可以選乙個火柴堆拿走若干根火柴。可以只拿一根,也可以拿走整堆火柴,但不能同時從超過一堆火柴中拿。拿走最後一根火柴的遊戲者勝利。本題的遊戲稍微有些不同 在第乙個回合中,第乙個遊戲者可以直...
GDOI2016模擬8 14數樹數
題目 給定一棵n 個節點的樹,標號從1 n。每個點有乙個權值。要求維護兩種操作 1.c i x 0 x 2 31 表示將i 點權值變為x 2.q i j x 0 x 2 31 表示詢問i 到j 的路徑上有多少個值為x 的節點 時間複雜度 n q log n q 2 空間複雜度 n q log n q...
GDOI2016模擬8 8旋轉
alice和bob發明了乙個新的旋轉遊戲。首先,bob給定n個數組成的序列,並把該序列平均分配成若干個塊,每塊正好包含k個數 k能整除n 第一塊由第1到第k個數構成,第二塊由第k 1個數到第2k個數構成,以此類推。接著,bob要求alice對這個序列進行一系列操作,操作有以下兩種 1.把每塊裡面的數...