兩個NOI題目的啟迪 皇后和算24

2022-04-07 08:00:03 字數 2637 閱讀 1619

論出於什麼原因和目的,學習c++已經有乙個星期左右,從開始就在做noi的題目,到現在也沒有正式的看《primer c++》,不過還是受益良多,畢竟c++是一種」低階的高階語言「,而且noi上的題目可以說是循序漸進。不僅僅是從asm、vb.net的角度看程式語言,這讓我對程式語言語言的理解有了一些深入。

這一篇來記錄一下」2.5基本演算法之搜尋「的兩個問題解決的過程。它們有一些類似之處,也有很大不同。

一、8皇后

這是乙個非常經典的問題:輸出在8*8的棋盤上,擺放8個相互無法吃掉的皇后的全部擺法。一般認為有92種擺法,其中有一些通過映象、旋轉相互重合。因為皇后可以橫向、縱向、斜向4個方向吃子且遠近不計,所以放上乙個皇后之後就會導致一些格仔沒法再放皇后了:典型的,我們在(0,0)放上乙個皇后之後,下次再放就要避開滿足x=0,y=0,x=y的格仔,這也是簡化演算法的基礎。這導致這個問題求解時,可以按行或按列依次搜尋,因為前一行(或列)放置皇后之後就不能再放皇后了。這使得每次遍歷都被限制在最多8格之內,從而形成了一顆」枝繁葉疏「的樹,可以用回溯法等深度優先演算法進行求解。

理論是美好的,實現的過程是殘酷的,我用了若干小時編寫這份**,但最終很多理論都沒有使用,所以寫出來的**沒有什麼特別的亮點,甚至自覺很醜陋,所以這篇只有算24的**。不過在求解過程中,有一些小技巧還是值得和大家共同討論的:

1、stack進行有序遍歷:將y=0的8個位置push,在迴圈中把y=1-7的push(如果存在可能解),在迴圈開始輸出y=7時的路徑,這些路徑就是解。

2、使用位棋盤,使用位棋盤可以大為加快記錄皇后4向攻擊位置(即不能再放皇后的位置)的計算速度:只需要讀取mask[i]然後與當前的位棋盤進行按位與運算就得到了放置這個皇后之後的情況。用位棋盤速度非常塊也非常節省空間,但是我在進行ull型別|運算的時候,發現高32位沒有被正確操作,可能是我的**問題,也可能是編譯器問題。可以用兩個32位來代替,速度也比運算元組快很多。

因為關於8皇后這一經典問題,網上有很多**,其中有一些質量比較高,很有參考價值,所以在這裡就不再贅述(很好,隱藏我的醜陋**成功)。

二、算24

這個noi問題是這樣的:

總時間限制: 3000ms 記憶體限制: 65536kb

描述給出4個小於10個正整數,你可以使用加減乘除4種運算以及括號把這4個數連線起來得到乙個表示式。現在的問題是,是否存在一種方式使得得到的表示式的結果等於24。

這裡加減乘除以及括號的運算結果和運算的優先順序跟我們平常的定義一致(這裡的除法定義是實數除法)。

比如,對於5,

5,5,1,我們知道5 * (5 – 1 / 5) = 24,因此可以得到24。又比如,對於1,1,4,2

,我們怎麼都不能得到24。

輸入輸入資料報括多行,每行給出一組測試資料,包括4個小於10個正整數。最後一組測試資料中包括4個0,表示輸入的結束,這組資料不用處理。

輸出對於每一組測試資料,輸出一行,如果可以得到24,輸出「yes」;否則,輸出「no」。

樣例輸入55

5111

4200

00樣例輸出

yesno

乍一看,好像挺簡單……於是,拿過來就寫:挨個拿出來和之前的結果運算(開始時把其中1個看作上次結果)、包括顛倒和括號,嘿……只得了5分。然後才想起來仔細分析題目,汗顏啊。這裡包括這樣一些運算過程:

只表示算式形式,而不代表順序,逗號通配運算子:

a,b,c,d

(a,b),c,d

a,(b,c),d

a,b,(c,d)

(a,b,c),d

a,(b,c,d)

以及(a,b),(c,d)

最後一種形式就是第一次5分的問題所在。」乙個乙個喂「的想法,導致最後一種形式被漏掉了。好吧,老老實實的:每次取2個得到乙個計算結果,把計算結果作為乙個待選運算數進行迭代:

//

遞迴計算過程

void msearch(double val,int

valcnt)

if(valcnt==1)

}else

nextval(val,valcnt,i,j,val[j]-val[i]);

if(val[j]!=0

) }}}

}

這裡有一行比較辣眼睛的**:

if(abs(val[0]-24.0)<=1e-13)

if(valcnt==1)

}else

nextval(val,valcnt,i,j,val[j]-val[i]);

if(val[j]!=0

) }

}}}//

用取出兩個數並加入結果的新陣列繼續遞迴

void nextval(double val,int valcnt,int idx1,int idx2,double

lastresult)

}newval[newvalidx]=lastresult; //

把結果加入新陣列

msearch(newval,newvalidx+1); //

用新陣列遞迴搜尋

}int

main()

flag=false

; msearch(val,4);

if(flag)

else

}}

陳躍峰的《兩個基礎的演算法題目》的解答

1 編寫方法,生成符合如下要求的乙個一維陣列。要求如下 1 該陣列的長度是20 2分 2 其中包含2組1 10之間的所有整數 5分 3 每個元素的位置不固定,也就是隨機數組 8分 4 該方法的返回值為該一維陣列 2分 5 規範 3分 2 編寫方法,返回乙個整數中出現次數最多的數字,如果出現的次數相同...

SAP和ISAP(網路最大流的兩個增廣路演算法)

isap是對sap進行優化後的演算法,isap時間複雜度為o v 2e sap的時間複雜度為o ve 2 sap include include include include using namespace std const int maxn 100 const int inf 1 30 1 i...

(1)用兩個棧實現佇列和(2)用兩個佇列實現棧

很經典的乙個演算法題,既考察了棧的性質,又考察了佇列的性質。我們可以定乙個stack1,stack2.入棧的時候直接入到stack1,當出棧的時候,先判斷stack2是否為空,為空的話,把stack1順序出棧壓入stack2.然後把stack2棧頂元素彈出。同理取front元素的時候也一樣。empt...