2020 noj演算法實驗考試

2021-10-10 07:33:34 字數 4502 閱讀 5033

思路**

0-1 揹包問題

思路**

素數環問題

思路**

二分查詢

0-1揹包問題

素數環問題

加1乘2平方

最長公共子串行

活動安排

描述

給定乙個單調遞增的整數序列,問某個整數是否在序列中。

輸入
第一行為乙個整數n,表示序列中整數的個數;

第二行為n(n不超過10000)個整數;

第三行為乙個整數m(m不超過50000),表示查詢的個數;接下來m行每行乙個整數k。

輸出
每個查詢的輸出佔一行,如果k在序列中,輸出yes,否則輸出no。

輸入樣例
5

1 3 4 7 1133

69

輸出樣例
yes

nono

二分查詢(binary search)也叫作折半查詢。二分查詢有兩個要求,乙個是數列有序,另乙個是數列使用順序儲存結構(比如陣列)。

二分查詢的原理及實現

二分查詢的實現原理非常簡單,首先要有乙個有序的列表。但是如果沒有,則該怎麼辦?可以使用排序演算法進行排序。

以公升序數列為例,比較乙個元素與數列中的中間位置的元素的大小,如果比中間位置的元素大,則繼續在後半部分的數列中進行二分查詢;如果比中間位置的元素小,則在數列的前半部分進行比較;如果相等,則找到了元素的位置。每次比較的數列長度都會是之前數列的一半,直到找到相等元素的位置或者最終沒有找到要找的元素。

我們先來想象一下,如果數列中有 3 個數,則先與第 2 個數進行比較,如果比第 2 個數大,則與第 2 個數右邊的數列進行二分查詢,這時這個數列就剩下乙個數了,直接比較是否相等即可。所以在 3 個數的時候最多比較兩次。

同理,在有 4 個數的時候,我們與中間數進行比較,一般中間數是首加末除以 2 算出來的,這時我們算出來的中間數是 (1+4)/2 等於 2,所以我們把要查詢的數與第 2 個數比較,若比第 2 個數小,則直接與第 1 個數比較;否則與後面兩個數進行二分查詢,這時的中間數是 (3+4)/2 等於 3,也就是後半部分的第 1 個數。再接著進行比較,相等則找到相應的元素,小於則沒有這個數(因為左邊所有的數都已經判斷過了),大於則繼續向右查詢。所以在 4 個數的時候最多比較 3 次。

以此類推,在 5 個數的時候最多查詢 3 次,在 6 個數的時候也是最多查詢 3 次。

下面我們以乙個實際的例子來看看二分查詢的操作過程。假設待查詢數列為 1、3、5、7、9、11、19,我們要找的元素為 18,下面進行二分查詢。首先我們找到中間的元素 7( (1+7)/2=4,第 4 個位置上的元素),我們要找的元素比 7 大,於是在後半部分查詢,現在後半部分數列為 9、11、19,我們找到中間元素,中間元素為 11,18與 11 比較,比 11 大,則繼續在後半部分查詢,後半部分只有乙個元素 19 了,這時直接與 19 比較,若不相等,則說明在數列中沒有找到元素,結束查詢。

對於這 7 個元素的數列,我們只查詢並比較了 3 次,是不是比較次數很少呢?

#include

using namespace std;

#define maxsize 50005

intbinarysearch

(int m)

;int a[maxsize]

;int b[maxsize]

;int m;

intmain()

cin >> n;

for(j =

0; j < n; j++

)for

(i =

0; i < n; i++

)return0;

}int

binarysearch

(int num)

else

if(num < a[middle]

)else

} cout <<

"no"

<< endl;

return0;

}

描述
需對容量為c 的揹包進行裝載。從n 個物品中選取裝入揹包的物品,每件物品i 的重量為wi ,價值為pi 。對於可行的揹包裝載,揹包中物品的總重量不能超過揹包的容量,最佳裝載是指所裝入的物品價值最高。

輸入
多個測例,每個測例的輸入佔三行。第一行兩個整數:n(n<=10)和c,第二行n個整數分別是w1到wn,第三行n個整數分別是p1到pn。

n 和 c 都等於零標誌輸入結束。

輸出
每個測例的輸出佔一行,輸出乙個整數,即最佳裝載的總價值。

輸入樣例
1 211

2 32 2

3 40 0

輸出樣例
1

【整體思路】

01揹包屬於找最優解問題,用回溯法需要構造解的子集樹。對於每乙個物品i,對於該物品只有選與不選2個決策,總共有n個物品,可以順序依次考慮每個物品,這樣就形成了一棵解空間樹: 基本思想就是遍歷這棵樹,以列舉所有情況,最後進行判斷,如果重量不超過揹包容量,且價值最大的話,該方案就是最後的答案。

在搜尋狀態空間樹時,只要左子節點是可乙個可行結點,搜尋就進入其左子樹。對於右子樹時,先計算上界函式,以判斷是否將其減去(剪枝)。

上界函式bound():當前價值cw+剩餘容量可容納的最大價值<=當前最優價值bestp。

為了更好地計算和運用上界函式剪枝,選擇先將物品按照其單位重量價值從大到小排序,此後就按照順序考慮各個物品。

【舉例說明】

對於n=4的0/1揹包問題,其解空間樹如圖所示,樹中的16個葉子結點分別代表該問題的16個可能解。

【演算法設計】

利用回溯法試設計乙個演算法求出0-1揹包問題的解,也就是求出乙個解向量xi (即對n個物品放或不放的一種的方案)

其中, (xi = 0 或1,xi = 0表示物體i不放入揹包,xi =1表示把物體i放入揹包)。

在遞迴函式backtrack中,

【時間複雜度&&優化】

因為物品只有選與不選2個決策,而總共有n個物品,所以時間複雜度為o(2n)。

因為遞迴棧最多達到n層,而且儲存所有物品的資訊也只需要常數個一維陣列,所以最終的空間複雜度為o(n)。

#include

int cur_weight, cur_value;

int max_value;

int c, n, time;

//time記錄求最大解的次數

int w[

100]

, v[

100]

, value[

100]

;void try (

int k )

else}}

intmain()

try (1)

; value[time++

]= max_value;}}

for( i =

1; i < time; i++

) printf (

"%d\n"

, value[i]);

return0;

}

描述
把1到20這重新排列,使得排列後的序列a滿足:

a. 任意相鄰兩個數之和是素數

b. 不存在滿足條件a的序列b使得:a和b的前k(0 <= k <= 19)項相同且b的第k+1項比a的第k+1項小。(即按字典序排列的第一項)

輸入
沒有輸入。

輸出
輸出a,兩個數字之間用乙個空格隔開,第乙個數字前面和最後乙個數字後面沒有空格。

#include

#include

#include

#include

using namespace std;

int a[21]

,book[21]

;bool isprime

(int n)

}return true;

}bool judge

(int m)

else

else

}else

//還未到第20個數字,還未成環

}else}}

void

print()

cout<

<

}bool dfs

(int n)

else

} book[i]=0

; a[n]=0

;}}return false;}}

intmain()

NOJ1130 演算法實驗三 polygon

時限 1000ms 記憶體限制 10000k 總時限 3000ms 描述在乙個周長為10000的圓上等距分布著n個點,即這n個點是乙個正n邊形的頂點。現在要另加m個點到圓上,新加的m個點可以任意選擇位置 可以與原有的點重合 然後將這n m個點中的一些點延圓周移動,最終使n m個點均勻分布,即在乙個正...

NOJ1043 演算法實驗三 跳馬

描述 在西洋棋中,馬的走法與中國象棋類似,即俗話說的 馬走日 下圖所示即西洋棋中馬 k 在一步能到達的格仔 其中黑色的格仔是能到達的位置 現有一200 200大小的西洋棋棋盤,棋盤中僅有乙個馬,給定馬的當前位置 s 和目標位置 t 求出馬最少需要多少跳才能從當前位置到達目標位置。輸入 本題包含多個測...

NOJ1149 演算法實驗四 旅遊預算

時限 1000ms 記憶體限制 10000k 總時限 3000ms 描述乙個旅行社需要估算乘汽車從某城市到另一城市的最小費用,沿路有若干加油站,每個加油站收費不一定相同。旅遊預算有如下規則 若油箱的油過半,不停車加油,除非油箱中的油不可支援到下一站 每次加油時都加滿 在乙個加油站加油時,司機要花費2...