今天總的講些演算法,會了的話...看上去好厲害的樣子:
1.老朋友動態規劃dp:
dp重點:
1.邊界條件,開頭不需處理的資料,比如斐波那契數列中的第一二項
2.轉移方程,後面的項需要根據前面幾項求出自身值的方程(等式)
套路:1.定狀態,
2.寫方程,
3.敲**
三種用法:
1.順著推,
2.倒著推,
3.記憶化搜尋,
舉個栗子——斐波那契:
1.倒著推:比較簡單,只寫方程:f[n]=f[n-1]+f[n-2]
2.順著推:**
#includeusing中間核心部分思想在於最新一項去更新後項,因為由遞迴公式可得當前f[a]只對f[a+1],f[a+1]產生貢獻,而倒著推思想在於用已經推過的值去更新最新一項。namespace
std;
intn;
int f[25
];int
main()
cout
return0;
}
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
從區間中列舉斷點,合併左右,找最優方案
例題:合併石子
**:
#includeusing5.其他(沒有套路,只能自己推轉移方程)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;
}
肥腸常烤非常常考
例題:數字三角形(終於有道做過的了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,像 ...