一些算法及題目總結

 

 

1. 廣告排名區間 


問題背景 
shifen廣告消費預估系統可以估計出一段時間內一個特定的廣告在檢索結果中排在各個位置的機率。比如系統對某廣告的輸出如下: 
p1 = 0.03, p2 = 0.08, p3 = 0.04 …… 
這說明該廣告展現在第1位的概率是 3%,展現在第2位的概率是 8%,展現在第3位的概率是 4%…… 

問題是:如何給出一個排名估計區間[i, j],使得廣告出現在該區間中的概率大於或等於一個預設值p,同時這個區間所包含的元素儘可能的少。也可用數學語言來描述:給定數p和數列 p1, p2, … , pn,求 i和 j (1 <= i <= j <= n),在滿足pi + pi+1 + … + pj >= p的前提下讓j-i 最小。 
一般來說,pi只需保留6位小數就足夠了。這樣,若令ai=106pi,a=106p,則a和所有的ai均爲[0,106]之間的整數。這樣就避免了對實數的處理。 
輸入格式 
第一行包含一個整數n (1 <= n <= 100,000)。 
以下n行每行包含一個[0,106]內的整數,依次爲a1,a2,…,an。這n個整數之和保證不超過106。 
最後一行包含一個[0,106]內的整數a。保證所有ai之和不小於a。 
輸出格式 
輸出僅一行,包含一個整數,即j – i的最小值。 
樣例輸入 





10 


18 
樣例輸出 

 

 

 

 

 

 2, 堆排序

堆排序很好用,可以排序出前幾個最大,最小值。堆排序中最重要的一步是堆調整。建堆的過程,實際上是對0~n/2的節點進行調整的過程。而排序的過程,事實上就是取堆頂元素然後堆調整的過程。示例代碼如下

 

3, 約瑟夫問題

 

N只猴子要選大王,選舉辦法如下:所有猴子按1-N編號圍坐一圈,從1號開始按順序1,2,,,m報數,凡報到m的猴子退出到圈外,如此循環報數,直到圈內只剩下一隻猴子時,這隻猴子就是大王。N和M由輸入文件提供,要求在輸出文件中打印出最後剩下的猴子的編號。數據規模

 

 

 

 

 

4,最長數字子序列問題。

給定一個字符串例如:sfjajf1234123jhjsdlfjakfsdlj123123123jflajsfdkas2342342。給出最長的數字子序列,並輸出該子序列的長度。當然可以掃描一遍,記錄所有的數字序列的起始地址,長度,比較找出最長的。但這顯然複雜了。可以在o(n)時間內搞定。也就是說僅需遍歷一遍。

 

 

5,亞特蘭數~

關於一下的幾種問題

 

1.括號化問題。

  矩陣鏈乘: P=a1×a2×a3×……×an,依據乘法結合律,不改變其順序,只用括號表示成對的乘積,試問有幾種括號化的方案?(h(n)種)

2.出棧次序問題

  一個棧(無窮大)的進棧序列爲1,2,3,..n,有多少個不同的出棧序列?

  類似:

  (1)有2n個人排成一行進入劇場。入場費5元。其中只有n個人有一張5元鈔票,另外n人只有10元鈔票,劇院無其它鈔票,問有多少中方法使得只要有10元的人買票,售票處就有5元的鈔票找零?(將持5元者到達視作將5元入棧,持10元者到達視作使棧中某5元出棧)

  (2)在圓上選擇2n個點,將這些點成對連接起來,使得所得到的n條線段不相交的方法數。

3.將多邊行劃分爲三角形問題

  將一個凸多邊形區域分成三角形區域的方法數?

  類似:一位大城市的律師在她住所以北n個街區和以東n個街區處工作。每天她走2n個街區去上班。如果她

  從不穿越(但可以碰到)從家到辦公室的對角線,那麼有多少條可能的道路?

  類似:在圓上選擇2n個點,將這些點成對連接起來使得所得到的n條線段不相交的方法數?

4.給頂節點組成二叉樹的問題。

  給定N個節點,能構成多少種形狀不同的二叉樹?

  (一定是二叉樹!

  先去一個點作爲頂點,然後左邊依次可以取0至N-1個相對應的,右邊是N-1到0個,兩兩配對相乘,就是h(0)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(0)=h(n))

  (能構成h(N)個)

 

 


h(n)=C(2n,n)/(n + 1) (n=1,2,3,...)

關於16個人買燒餅的題目,G(16)=h(8)=c(16,8)/9=1430

6,  Fibonacci分解

定理 任意自然數n的Fibonacci分解是唯一的。(F1=1,F2=2)

    設不大於n的最大的fibonacci數爲Fb

    Fibonacci分解爲:F(n)=Fb+F(n-Fb);

Fibonacci分解是唯一的。

同時附跳棋問題解決方法。跳棋問題:一系列相當長的個子,某些個子裏面放了棋子,如果格子裏面有棋子,就可以拿走其中的一顆,同時在這個格子的左邊兩個格子裏面放一顆。如果連續兩個格子裏面都有棋子,可以分別從兩個格子中各拿走一顆,之後再他們右邊的格子裏面放入一顆。

爲什麼用fabonacci分解?因爲以上題目中的兩個操作是可逆的。對於三個連續格子,每個格子放1,可以看做後一個是前兩個之和。只用給這些格子加上fabonacci的權重就可以了。然後用格子中的棋子乘以格子的權重之和爲n,分解n。得到唯一的一組解。對應的格子中放1就是解。解是唯一的。

    至於實際的編程,還要考慮更多的問題。

 

7,序關係計數問題

 

用關係運算符"<"和“=”來表示幾個字母的排列。如果是三個數將由13種不同的排列。由於A=B和B=A是一樣的。

 

那麼首先想到的是遞歸的方法。

 

不妨設 總共有N個字母。對於N的情況,只用求出當前連接符爲<和當前連接符爲=的兩種情況。=的情況下,我們要求,=號前面的字符ascii小於等號後面的字符。

 

這樣的話。對於N個字母的情況。F(N,E,1)=F(N-1,E-a,1)+F(N-1,E-a,2)

對於上述遞歸式解釋。E代表字母集合,a代表該次遞歸用掉的字母,最後的一個參數代表字母表搜索開始位置。1代表從字母表第一個開始。當關係爲<時,可以從字母表第一個開始,搜索未被用過的字母。當關係爲=時,只能從當前字母的下面一個開始。

< ;p> 

 

該算法計算很慢。原因是計算了太多重複的子結構

如果當前關係爲<時,不管當前選用了什麼字符。如果還剩k個的話,這k個字符組成的關係的數字一樣的。例如當前選擇了a,或者選擇了b,在當前關係爲<的時候不影響下一步的關係數。然而,在這裏計算了太多。

 

事實上,改進到這裏,這個算法還有改進的餘地。換一個角度來思考。

當前只有一個字符的時候F(1)=1;f(2)=3;這裏的f跟上面改進後的一樣。

想想一下有3個字符的時候的情況。一個字符相等的情況(其實就是都不等),前兩個字符相等的情況,,三個字符相等的情況之和3*f(2)+3*1+1=13。

 

 

那麼可以這麼來思考,F(n)=C(N,1)*F(n-1)+C(n,2)*F(n-2)。。。+C(n,n)*F(0),令F(0)=1

那麼根據上述算法

F(1)=C(1,1)*F(0);

F(2)=C(2,1)*F(1)+C(2,2)*F(0)=3

F(3)=。。。

從而算出F(n)

 

 

 

實際運行一下,時間差距非常之大,尤其在n>10的時候尤爲明顯。未優化的代碼運行速度很慢,所以沒有必要設置成double(8字節),int(4字節)足以。改進之後的,可以計算到double的情況。

 

8,用二分查找在無序數組中查找第k大的數字

 

 

 

 

 

 

 

查找的方法:隨機找一個數字,然後將小於它的放在它的左邊,大於它的放在它的右邊。

 

 操作完之後,它在第i個位置,如果i=k,則找到了,否則如果i>k,則在1~i的範圍內找第k大,否則,在i+1~n的範圍內找k-i-1個數

算法複雜度爲O(n)

 

 

 

 

9, 關於枚舉01串的一種寫法

 

10 最長公共子序列

這個是動態規劃的基礎題目。動態規劃就是遞推和重複子結構。

確定了遞推關係後。找到一個能極大地減少重複運算的子結構至關重要。選的好了,時間效率會很好。

 

這個問題,不妨設第一個串爲a,長度爲n,第二個串爲b,長度m。那麼最長的子序列長度爲f(n,m)

當a[n]=a[m]時

f(n,m)=1+f(n-1,m-1)

否則f(n,m)=max(f(n-1),f(m-1))

同時建立一個存儲計算過的f(x,y)的矩陣,如果計算過了就直接使用

 

 

程序如下所示

 

 

 

 

11 賽程安排,要求,每人每天只能比賽一次,有2^m個選手,給出一種安排方式,讓所有的選手在2^m-1天內,每兩個都能夠至少比賽一次。

這個題目很有規律。給出問題規模m,2^m個選手,2^m天。那麼不妨做出他們的天/人矩陣。當只有一個人的時候,m=0,則只能是1,當問題規模爲m+1時,可以將該矩陣分解爲4個矩陣。

g(m+1)= |A B| B中的元素等於A中相應位置的元素+2^m,C與B一致,D=A,那麼就可以使用遞歸的方法了。

       |C D|

 

12,計算子n維體的階級和自己做個記號。這道題的思維過程和方式很值得學習。實際上,我們從小接受的數學訓練也不過如此。只是,隨着我們的成長,純數學的東西做的少了,變得愚鈍了罷了

 

n維體定義爲P((S1,T1),(s2,T2),(s3,T3))

n維體的階積爲(T1-S1)*(T2-S2)...

若T>T1,S<S1,則說新的n維體爲上一個的子n維體。T,和S的取值爲1,2,3,。。。,n

 

題目要求:求給定n維體的所有子n維體的階積之和

 

這個題從表面上kan很複雜,對於一維來說,總共有(T-S+1-1)+(T-S+1-2)+。。。+(T-S+1-(T-S))種取法,不妨設T-S=A

則,則共有A*(A+1)/2種取法,在n維空間下的取法將會很大,就t大老師的書上所講的是O(m^(2^n)),m表示Ai的一般規模。

 

實際上可以進行降維處理不妨設一維下的階積爲F(A1),那麼2維下的實際上是F(A2)*F(A1),n維依次。。。

而一維下的階積爲F(A)=1/6*a(a+1)(a+2)

 

在n維情況下就很容易算出來了。問題規模變成了O(n)

提示:遇到問題不要先一味的想最爲基本的算法,尤其是基本的方法問題規模很大的時候。不妨羅列試探一下,找到問題的規律,可能有更好的解。

13,求最多因子數

給定一個範圍0<n<=M<=1億,M-N<1百萬,求n~m之間擁有最多因子的數

 

首先,可以回顧一下,如何對一個數做質因子分解。很簡單,從2開始,如果包含該因子,輸出該因子,並且原數字除以該因子。代碼如下

如何計算一個數的因子:

給定0~n的範圍,在這個範圍內,用兩重循環

對包含i,j的因子數+2

例如這麼來做

for(int i=1;i<floor(sqrt(n));i++)

    for(int j=i+1;j<n/j;j++)

         f[i*j]+=2;

 

但是對於這道題,數字的取值範圍很大。不可能開一個一億的數組,或者一百萬的數組

但是可以採用化整爲零的方法。將這些數字分成3w一組(T大老師的書),然後來做

代碼如下

14,已知a和n,計算a^n

當然可以把a自乘n次。但也有簡便的算法。

例如

a=2,n=100=2^6+2^5+2^2。事實上,我們只用作6+3次乘法就可以算出結果,其中的6次是計算到a^(2^6)所用的乘法次數。3次是每一項乘到結果用的次數

 

對此,做一簡單實現,普通乘法

同時,由於a^n通常會涉及到大數的運算。做了大數高精度乘法的實現

測試例子

 

2

10

1024

 

 

 

 

2 100

1267650600228229401496703205376

 

 

一百次方的幾乎是立刻得到結果

 

15, 奶牛網球賽

 

N個奶牛,每個可以贏自己排名後的,也可以贏自己排名前k個的。問,最大的冷門可能是哪個?

 

方法:實際上,加入第m個奶牛可以贏,那麼排名前面的也可以贏。假設可以贏爲1,不可能爲0.則N個奶牛可以組成一個1,0的序列。一邊爲0,一邊爲1,只用求他們之間的臨界點就行。

 

用二分枚舉。mid可以麼?可以,則區間爲mid~end,否則,start~mid-1。這樣就可以保證找到最後的可以的那一個。

 

(該題做個記號)

 

 

用二分枚舉(記號)

二分枚舉的另一例子:

城堡圍圈士兵發獎章的問題。如果不圍圈,直接貪心算法。每次儘量分給已經用過的獎章類型。但是圍圈的話,就需要考慮每個和第一個的人的相同的獎章的數量。這種情況下,動態規劃是可以的。但是時間複雜度稍微高一些。如果使用x個獎章可以,則x+1個獎章也可以。所以可以使用二分枚舉。來枚舉最極限的那個點。這個點實際上就是我們想要求的。實際的思考過程還要複雜一些。(該題目不寫程序了,留個記號)

二分枚舉的另一個例子:

推銷員的旅行。從一個城市到另一個城市,在一個城市待一個小時,作宣傳,然後到另一個小時。假如他只能查詢每天的12點的某個城市到一個城市的航班。假設每個城市之間都有航班,但僅有一架,不間斷往返飛行,飛行時間1小時。該推銷員需要打電話來查尋。

 

這個題目的二分搜索比較隱晦。 當有i個城市已經安排的時候,安排第i+1個城市的時候,如果第i個城市指向i+!,則直接添加到最後。如果i+1指向第一個城市,直接添加到第一個位置。如果不屬於以上的兩種情況。則在其中的某個一定可以加進去。如果2不可以,則2一定指向i+1,由於i+1指向i,所以一定能找到。

       用二分搜索的方法,如果mid元素指向i,則在後半部分一定能夠找到,則查找後半部分,前半部分有所有都指向i的可能,但並不是說沒有可能插入。只是後半部分插入的可能性更大而已。

代碼如下,其中沒有實現的函數爲查詢函數,即航班系統提供的查詢函數。

 

二分搜索的另一個例子

 

有n個石頭,k個框子。把n個石頭按順序放入k個框子,比如1~3放入1,4~6放入2,要求最大重量的框子的重量最小的放法。

該題目可以用動態規劃的方法

設f(i,j)表示i個石頭放入j個框子的最佳放法...暫時做個記號

用二分法探測

總石頭重量sum,[1,sum]之間採用二分探測。例如mid可以,則在1~mid間探測,否則在mid和sum之間探測,這樣的時間代價遠小於動態規劃

代碼如下

 

二參數二分搜索舉例

 

有n個題目,至少選擇連續的k個,使得選擇的題目的分值和難度比最大。

 

設,分值爲Ai,難度爲Bi,則分值難度比爲(Ai+...+Aj)/(Bi+..+Bj)>=p

這樣就可以改寫成,(Ai-Bi*p)+...+(Aj-Bj*p)>=0,我們只用二分查找這個p就可以了

 

這樣的話,時間複雜度(NlogT),當然也可以暴力搜索,時間複雜度可以爲(N^2)

代碼略

 

 16,錯排問題。

例如1,2,3,4,每個數字不在自己的位置上就是錯排,求錯排數量和錯排方案

求數量方案一,F(n)=n!-C(n,1)F(n-1)-C(n,2)F(n-2)-...-C(n,n)F(0)。F(0)=1;F(1)=0;

該方案不能用來求錯排方案

方案二:求錯排的兩種方式

            方式a,n與1,n-1交換,剩下的n-2個元素錯排

            方式b,n-1個錯排,每個元素和n交換

數量    F(n)=(n-1)(F(n-1)+F(n-2)),F(1)=0,F(2)=1

 

實際操作中還需要一些技巧來實現方案二的方式a, 代碼如下

17晚餐。媽媽燒了m個骨頭分給n個孩子,每個孩子有需求大於min,小於等於max,骨頭必須全部分給孩子,求最多的方案數目

 

根據鴿巢原理,把m個鴿子放到n個籠子裏,籠子可以爲空的情況下有C(m+n-1,n-1)种放法。則每個減去min後,算出來的結果是沒有考慮上限的做法。根據容斥原理,可以計算出集合的並(每個集合爲單個孩子max下的種類)

代碼如下 

18, 單色三角形問題

一個完全圖,每兩個點之間的連線不是紅色就是黑色,求單色三角形的個數。

方法一,枚舉所有的三角形。

方法二,三角形個數爲c(n,3),異色三角形的個數:只要兩條邊異色就可以了。則只用求單點異色邊對數,然後,總對數就等於單點異色邊對數之和的二分之一,一個點的邊數爲n-1,紅色爲x,則黑色爲n-1-x

代碼略

19, 籃球隊員身高問題

 n個籃球隊員,平均身高2000mm,身高範圍1950~2050mm。求一個排列,使得對於任意一個給定的k,任意k個連續隊員的身高之和與k*2000之差的絕對值小於100

 

方法:首先,預處理,所有的減去2000,有負有正,分爲兩個數組。初始總值爲0.如果總值加上一個正值小於50,則加上該正值,否則,加上一個負值。由於條件的限制,每個數值的絕對值一定是小於50的。最終一定能找到這樣一個序列,因爲所有的隊員的平均身高爲0(2000)

代碼如下

 

20, 排列問題

 

在整數1,2,。。。,n中,有些排列滿足下面的性質:該排列中除了最後一個數字以外,每個整數後面都跟有一個同它相差爲1的整數。例如:N=4,排列1432滿足上述性質。求,如果 任意指定p個位置的值,求最多有幾個排列滿足如上性質

 

這種排列滿足一下兩條性質

a,任何一個排列的後k位是若干連續整數的集合

b,如果一個排列的後k位(1<=k<=n)是軟干連續整數組成的集合,則這個排列滿足題目所述的性質。

 

動態規劃的方法即可。設s爲起始的數的大小,r爲連續的多少數的個數

 

g(s,r)=g(s+1,j-1),若第1個位置爲s,即倒數第j個位置爲s

   g(s,j-1),若第1個位置爲s+r-1,即倒數的第j個位置爲s+r-1

   不確定則爲上述兩個之和

 

代碼如下

 

 

21,pku 2018

題目是 讀入一列正數,以及一個數F,求一段長度大於等於F且平均值最大的子串範圍F<=N<=10^5

 

這個題目我花了一些時間,做了一下,驗證了一些數據都是正確的,但是提交的時候卻總是錯的。

這個問題網上也有多種解法,有一個高人用O(N)方法,但是卻沒有說明,我按照這個算法提交的居然是超時的錯誤

代碼如下

另外一種算法,是利用下凸折線,這個算法比較好,利用了幾何性質

代碼如下

這個題目算是先留下個紀念吧,好好地思考一下,到底是哪裏錯了。原來的錯誤在於題目要求的輸出用1000*ncows/nfields的形式,我直接用一個double的ans*1000,這顯然是錯誤的,一個是整形,一個帶小數。但後來修改之後依然不對。

 

看了別人的解法,這個方法是實現的凸曲線比較好的方法

 

 

22. 放水

N層儲水地下建築,第一層最靠近地面,第N層就是最底層。第N層有泄水管道和外面的一個大水池相連。每一層都可以蓄水,但有限制:規定第i層的蓄

 

水池的蓄水上限位Li。初始時,每一層有水wi,如果一層的存水量大於該層的上限,該層所有的水都會流入下一層。自動防水的過程不需要費用。也可

 

以選擇手動放水,手動放水每層的費用是Pi,求最小費用使得最下一層的水全部流走。

 

從最頂上一層,即就是第一層開始,放第一層的全部的水,然後計算下面需要手動放水的層,一層一層的放,最後放完。然後從第二層開始,

 

就這樣一層一層的算,求最小值。

可以優化的地方,如果從第二次開始,也就是說第二次爲最頂上手動的,則當前層的L減去的前面的累積和這一塊可以優化。

這道題目還是比較簡單的。但是剛纔看了《老男孩》內心感慨萬千,思緒亂飄,居然還調試了一會~~我還年輕~~Rabbit說我們都還正年輕着呢~這首歌寫的很不錯~當年看了k歌情人之後就反覆的聽那首歌~~彷彿歌不是爲了電影,電影是爲了歌而寫的。~~

代碼如下

 

 

 

 

23, 數列轉換。一列數a1,a2,a3,a4,a5...可以做如下操作

(a1,a2,a3)->(a1+a2,-a2,a2+a3)

給定一個數列的初始狀態和一個結束狀態,判斷是否能夠通過上述的操作進行轉換得到

 

直觀的看,經過這種操作之後,數列的和不變,但事實上這個並不能決定例如(1,2,3),(1,3,2)就不能變化得到

 

我們關注部分和S1=a1,S2=a1+a2,S3=a1+a2+a3,則變化前後位(S1,S2,S3)->(S2,S1,S3)

事實上就是部分和交換位置,變換位置的部分和和前面的部分和交換位置。

 

所以判斷能否得到,只用判斷經過排序的部分和是不是對應的相等。如果相等則可以,如果不等,則不可以。

整個時間代價就是排序的時間代價,計算部分和在輸入的同時完成

需要實現排序算法,O(nlogN),也可以直接使用qsort,或者java.util.Arrays.sort().

題目比較簡單,實現也沒有難度,代碼就不寫了

 

24 排數遊戲

 

初始時,有一系列的數排成一行1~30000,數字i的位置在i列,遊戲有兩類指令

合併指令 M i j,將第i列的數字放在第j列的後面

查詢指令 C i j, 如果i,j在相同的一列,輸出他們之間的間隔,否則輸出-1

 

25 最優聯通子集

//題目:在座標平面內的整點集中,稱距離爲1的兩點相鄰,即相鄰關係爲上下左右

 

//如果S中存在互不相同的點序列R,Q1,Q2,...,Qk,T。其中任意相鄰兩項的點相鄰,

//則稱在整點集S中,存在R,T的一條道路。如果S中任意兩點之間都有且只有一條路徑,

//則稱S爲單整點集。現給定S並給S中所有點賦一個權,求單整點集B,B是S的子集,且B的權和,最大

 

 

相當於求樹的權的最大子樹

代碼

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章