清北學堂(2019 4 30 ) part 3

2022-04-12 03:02:00 字數 4297 閱讀 6007

今天總的講些演算法,會了的話...看上去好厲害的樣子:

1.老朋友動態規劃dp:

dp重點:

1.邊界條件,開頭不需處理的資料,比如斐波那契數列中的第一二項

2.轉移方程,後面的項需要根據前面幾項求出自身值的方程(等式)

套路:1.定狀態,

2.寫方程,

3.敲**

三種用法:

1.順著推,

2.倒著推,

3.記憶化搜尋,

舉個栗子——斐波那契:

1.倒著推:比較簡單,只寫方程:f[n]=f[n-1]+f[n-2]

2.順著推:**

#includeusing

namespace

std;

intn;

int f[25

];int

main()

cout

return0;

}

中間核心部分思想在於最新一項去更新後項,因為由遞迴公式可得當前f[a]只對f[a+1],f[a+1]產生貢獻,而倒著推思想在於用已經推過的值去更新最新一項。

3.記憶化搜尋:**:

#includeusing

namespace

std;

int f[25

];bool vis[25

]; //用這個bool陣列記錄是否推過

inline

int dfs(int

n)int

n;int

main()

聽說記搜能做出來的動規題,前兩種一定能做出來...

分類:1.數字dp

按照十進位制每一位dp,自己寫的**(用動規思想寫出的偽高精...):

#includeusing

namespace

std;

int xn[15],xm[15

];int

n,m;

int v[15

];int

main()

while(m>0

)

for(int i=tn-1;i>=0;i--)

v[i]=v[i+1]*10+xn[i]-xm[i];

printf("%d

",v[0]+1

);

return0;

}

大佬的:

#include#include

#include

#include

using

namespace

std;

int f[10010][2],z[10010

],l,r;

int solve(int

x)//

存一下x的十進位制表示

n--;

memset(f,

0,sizeof(f));//

要做兩個動態規劃

f[n+1][1]=1

;

for(int i=n;i>=0;i--)

for(int j=0;j<=1;++j)

else}}

return f[0][0]+f[0][1

];

}int

main()

主要思想是分類討論,討論每次處理位數是否相等

2.樹形dp

例題:求n個節點的樹有幾個節點(exm?!)

我其實想用前向星遍歷求結果來著,還是練練dp吧,

主要思想:

根據子樹考慮

每個葉節點的子樹節點個數為1,非葉節點的為所有子樹的節點數+1(自身)

偽**:

inline void dfs(int

p) f[p]++;

}

大概正確吧...

樹的直徑:

給定一棵樹,樹中每條邊都有乙個權值,樹中兩點之間的距離定義為連線兩點的路徑邊權之和。樹中最遠的兩個節點之間的距離被稱為樹的直徑,連線這兩點的           路徑被稱為樹的最長鏈。後者通常也可稱為直徑,即直徑是乙個數值概念,也可代指一條路徑

現給一棵樹,求其直徑

思路:設f[p][0]為p點的最長路,f[p][1]為p點的次長路,分別儲存。

需根據子樹推導,對每個節點進行討論,對於葉節點,其沒有子樹,故無法進行討論,對於其他節點,則討論其子樹,尋找每個子節點的最長路及次長路,然後        按照方程取:

f[p(當前節點)][0]=max(f[p1(子節點1)][0],f[p2][0],f[p3][0],..........,f[pn][0])+1

f[p(當前節點)][1]=max(f[p1(子節點1)][0],f[p2][0],f[p3][0],.....(加特判不算上一步中取到的點).....,f[pn][0])+1  //因為要去最長路徑,所以顯然要取最長路徑,而不是         次長路,此處容易誤認為次長路需從次長路中選。

每次處理時用乙個變數「sum」取max來維護路長總和,以保證結果一定是最長最優,畢竟難免出現以下這種鬼圖的存在...(繪圖**:???)

所以根節點並不一定是最長路徑(直徑)經過的點,所以要對每個點進行處理,萬一直徑的根節點在哪個深山老林裡...

3.狀壓dp(聽說是最難的)

一般空間o(n2*2n)

時間o(2n*n)

一般接受n<=20.

(順便說一下:n<=1000,o(n2))

(n<=100,o(n3))

(n<=105,o(n log n))

(n<=106,o(n))

(n<=12,不要考慮複雜度了上暴搜吧)

tsp問題:

平面上有n個點,問把每個點都走一次的最短路徑,並且只能為鏈,不能為樹(更不能是圖),如下:

狀壓(狀態壓縮),用乙個數表示乙個集合,比如表示上圖的路徑

用二進位制實現,如下:

對於7 6 5 4 3 2 1,儲存路徑狀態為1 4 6

即為0 1 0 1 0 0 1,

因每個元素對於乙個狀態來說只有在其中或不在兩種狀態,可用1與0表示,而對於不同元素

其對應二進位制位有獨特的位置與權值,所以每一種狀態都有唯一的十進位制數與其對應

其狀態用f[s][i]表示,s為路徑壓縮結果,即已經走過的點的集合對應十進位制數,j為當前停留點

4.區間dp

從區間中列舉斷點,合併左右,找最優方案

例題:合併石子

**:

#includeusing

namespace

std;

const

int maxn=205,inf=0x7fffffff/2

;int

f1[maxn][maxn],f2[maxn][maxn];

inta[maxn],sum[maxn],n,ans1,ans2;

intmain()

for(int i=1;i<=n*2;i++)

for(int l=2;l<=n;l++)

f1[i][j]+=sum[j]-sum[i-1

]; f2[i][j]+=sum[j]-sum[i-1

]; }

ans1=inf;

ans2=0

;

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

}cout

return0;

}

5.其他(沒有套路,只能自己推轉移方程)

肥腸常烤非常常考

例題:數字三角形(終於有道做過的了qaq)

**:

#include#include

#include

#include

#include

//懷念不用萬用檔案頭的日子

using

namespace

std;

intn;

int v[1005][1005

];int ans=0

;int

main()

例題*改

對於每項v[i][j]%m,求其最大

多開乙個維度,[k],k表示%m剩下的值,dp方程如下:

if(f[i-1][j-1][(k-a[i][j])%m]||f[i-1][j][(k-a[i][j])%m])

f[i][j][k]=true;      //這裡f陣列為bool,結果直接輸出k

清北學堂(2019 4 29 ) part 2

主要內容資料結構 1.二叉搜尋樹 一棵二叉樹,對於包括根節點在內的節點,所有該節點左兒子比此節點小,所有該節點右兒子比該節點大,感覺好像二分.每個節點包含乙個指向父親的指標,和兩個指向兒子的指標。如果沒有則為空。每個節點還包含乙個key值,代表他本身這個點的權值 常用操作 插入乙個數,刪除乙個數,詢...

清北學堂 2017 10 01

problem 1.alien input file alien.in output file alien.out time limit 1s memory limit 128m 小y 最近正在接受來自x3 星球的外星人的採訪。在那個星球上,每個人的名字都是乙個正整數。所有在這個星球上的居民都是相互...

清北學堂 2017 10 06

因為是剛聽完課所以想把思路記下來,有一些其實也是一知半解的,如果有dalao可以幫忙講解那真是再感謝不過了。還有為什麼我畫圖這麼醜,哇的一下哭出聲 problem a.最佳進製 如今我們最常用的是十進位制,據說這是因為人有十根手指。但事實上這並不是十分方便,10 只有四個因子 1 2 5 10,像 ...