一句話歸納:若是之後能用鏈式前向星的話就儘可能用鏈式前向星 別用vector鄰接表html
由於我之前學圖論的時候,先接觸到的就是vector鄰接表的寫法,因此後來一直都是用vector鄰接表的寫法,後來也接觸到了鏈式前向星的寫法,而後那時候也瞭解到了vector鄰接表與鏈式前向星有內存性能上的差別,由於vector擴充時是默認多申請50%的內存空間,因此一些特別變態的題目可能會卡內存只能用鏈式前向星的寫法寫。不過當時也沒特別在乎,也想着到時候看邊數量特別大的話再說,vector鄰接表也寫慣了,但是最近竟然被卡了兩道時間的題目,讓我意識到可能鏈式前向星寫法與vector寫法還有時間上的差距,我猜與STL實現上有關。算法
深度優先遍歷在編碼上可使用棧或者遞歸實現,當使用遞歸時就叫作回溯法,,八皇后問題-回溯法,能夠求解全部可能的解,而廣度優先通常不能夠求得全部解,可是可應用於最優解問題,利用分支限界的思想,因此通常求解最優化問題使用廣度優先,深度優先也能夠。。數組
另外廣度優先求圖中兩點最短路徑,要求是不帶權或者每條邊的權值相等。若是帶權就只能使用迪傑斯特拉算法。ide
01揹包n行m列填表模塊化
eg:number=4,capacity=8函數
ipost |
1性能 |
2優化 |
3編碼 |
4 |
w(體積) |
2 |
3 |
4 |
5 |
v(價值) |
3 |
4 |
5 |
6
|
void FindMax()//動態規劃 { int i,j; //填表 for(i=1;i<=number;i++) { for(j=1;j<=capacity;j++) { if(j<w[i])//包裝不進 { V[i][j]=V[i-1][j]; } else//能裝 { if(V[i-1][j]>V[i-1][j-w[i]]+v[i])//不裝價值大 { V[i][j]=V[i-1][j]; } else//前i-1個物品的最優解與第i個物品的價值之和更大 { V[i][j]=V[i-1][j-w[i]]+v[i]; } } } } }
由此能夠得出遞推關係式:
1) j<w(i) V(i,j)=V(i-1,j)
2) j>=w(i) V(i,j)=max{ V(i-1,j),V(i-1,j-w(i))+v(i) }
g) 填表,首先初始化邊界條件,V(0,j)=V(i,0)=0;
h) 而後一行一行的填表,
1) 如,i=1,j=1,w(1)=2,v(1)=3,有j<w(1),故V(1,1)=V(1-1,1)=0;
2) 又如i=1,j=2,w(1)=2,v(1)=3,有j=w(1),故V(1,2)=max{ V(1-1,2),V(1-1,2-w(1))+v(1) }=max{0,0+3}=3;
3) 如此下去,填到最後一個,i=4,j=8,w(4)=5,v(4)=6,有j>w(4),故V(4,8)=max{ V(4-1,8),V(4-1,8-w(4))+v(4) }=max{9,4+6}=10;因此填完表以下圖:
每次訪問0入度集合時查看大小,當元素多於1的時候可行的選擇就出現了分歧——便可斷定此DAG的拓撲排序不惟一(固然本題的信息在不斷更新,因此不能馬上判死)。
1.anagram :變位詞 -
dfs,bfs複雜度通常是 ∑(每一個狀態的決策)
若是採用鄰接表存儲,通常狀況下複雜度爲O(E)(邊數)
一個有向無環圖(DAG)一般能夠表示某種動做序列或者方案,而有向無環圖的拓撲序列一般表示某種方案切實可行。
拓撲排序就是解決對有向圖的點進行線性排序的相關問題
LL hh = s/3600;
LL mm = (s%3600)/60;
LL ss = (s%3600)%60;
3.【矩陣快速冪】:
由於F(2)和F(1)是已知的,當n>=3時,每次都乘以矩陣B,就能推出下一個矩陣。而矩陣的第一行第一列的元素就是所求的結果。
1.
upper_bound()是返回第一個>x的數的下標
lower_bound()是返回第一個>=x的數的下標
2.
for(int i=0;i<n;i++) cnt+=lower_bound(a+i,a+n,a[i]+x)-(a+i)-1;//與a[i]差值小於x的個數 //https://blog.csdn.net/sgh666666/article/details/79253239
3.
upper_bound(a+i+1,a+n,d)-a;//找出這個數出現的最後一個位置的後一個位置
5.
1.lower_bound(a,a+n,d)-a,返回a[i]<d的個數。
2.upper_bound(a,a+n,d)-a, 返回a[i]<=d的個數。
6.
fill(a,a+n,x); 將數組a0~an位置賦值爲x。
7.發如今兩個不一樣數組和自身裏面的二分搜索不同
兩個不一樣數組:
for(int i=0;i<n;i++) cnt+=m-(upper_bound(b,b+m,num/a[i])-b);//查找是否比num大的元素的個數
自身[本數組]:
for(int i=0;i<n;i++) cnt+=m-(upper_bound(a+i+1,a+m,k-a[i])-a);
8. cbrt(a * b);
//求一個數的三次方程
9.
字符串的前綴是指字符串的任意首部。
好比字符串「abbc」的前綴有「a」,「ab」,「abb」,「abbc」。
一樣,字符串的任意尾部是字符串的後綴,「abbc」的後綴有「c」,「bc」,「bbc」,「abbc」
10.
11.
狀態既能夠指一個階段上做決策時所依據的天然情況和客觀條件,又能夠指一個階段上所做決策後的結局情況,故一個階段的狀態常有首、末狀態之分,以區別階段上決策的出發點和結局情況。但,通常地,人們每每僅選擇各階段的首、末狀態之一,做爲各階段的狀態,因此,當談到各階段的狀態時,要麼都指的是各階段的首狀態,要麼都指的是各階段的末狀態。
在前面的概念中,咱們看到了兩種不一樣的狀態表達方式:各階段的首狀態與各階段的末狀態
這裏想要說的就是,當讀者在作動態規劃問題時:
(1)若是狀態轉移方程中的S(k)表示的是各階段的首狀態:即:S(k) =S(k-1) + x(k-1),此時使用逆推法; S(1) = 最大數量
(2)若是狀態轉移方程中的S(k)表示的是各階段的末狀態:即:S(k) =S(k-1) + x(k),此時使用順推法。 S(n) = 最大數量
結論:
順推法與逆推法中遞推公式的不一樣致使使用順推仍是逆推方式的不一樣。
12.用memset賦值就算是0x3f3f3f也不行 ,只能0 / -1
13.
連續揹包(bag)
【問題描述】
從T組物品中選出一些物品,放入揹包中,求剩餘空間的最小值。
限制條件:從每組物品中挑選物品必需要選取連續的一段。就是說,若是這組物品共有n個: 物品一、物品二、物品三、…、物品n,那麼只能選取物品i、物品i+一、…、物品j,其中1<=i<=j<=n,或者不選。
那麼所求性價比最高的,直到超出揹包容量
14.01揹包記錄路徑:
f數組是從上到下、 從右往左計算的。 在計算f(i, j)以前,f[j]裏保存的就是f(i- 1 , j)的 值,而f[j-W]裏保存的是f(i- 1 , j-W)而不是f(i, j-W)——別忘了j是逆序枚舉的,此時f(i, j-W)尚未算出來。 這樣,f[j] =(max[j] , f[j-V]+W)其實是把保存在f[j]中,覆蓋掉f[j]原 來的f(i-1, j)。 提示9-17:在遞推法中,若是計算順序很特殊,並且計算新狀態所用到的原狀態不 多,能夠嘗試用滾動數組減小內存開銷。圖9-6 0-1揹包問題的計算順序 滾動數組雖好,但也存在一些不盡如人意的 地方,例如,打印方案較困難。 當動態規劃結束 以後,只有最後一個階段的狀態值,而沒有前面 的值。 不過這也不能徹底歸咎於滾動數組,規劃 方向也有必定責任——即便用二維數組,打印方 案也不是特別方便。 事實上,對於「前i個物 品」這樣的規劃方向,只能用逆向的打印方案, 並且還不能保證它的字典序最小(字典序比較是 從前日後的)。
15.
多重揹包和01揹包、徹底揹包的區別:多重揹包中每一個物品的個數都是給定的,可能不是一個,絕對不是無限個。
19.累加或者乘積必定注意用long long
1.模擬通常模塊化,方便查錯。
2.看清題目。分清楚石子歸併仍是貪心/哈弗曼樹;01揹包仍是暴力枚舉(cf慘痛教訓)
3.搜索和動態規劃是在多種策略中選取最優解,貪心算法則不一樣。它遵循某種規則,不斷地選取當前最優策略。
4.priority_queue的用法:
priority_queue實際上是C++STL中的一個神奇的容器。翻譯成中文叫作「優先隊列」,其實至關於個heap(堆),咱們能夠利用它來實現簡單的堆操做,避免了手打堆得麻煩,注意使用前須要引用頭文件:
定義一個優先隊列須要這樣,降序排列處理最大數:std::priority_queue<int> q; //q是隊列的名稱,能夠隨便起名,int是類型說明,經常使用int和long long
然而,這樣定義的優先隊列是數大的元素優先級高,先被彈出隊列,說白了就是降序排列。priority_queue只能對最大數進行操做,沒法處理最小數。如果想要升序排列處理最小數,也很簡單。
升序排列處理最小數:std::priority_queue<int,vector<int>,greater<int> > q;
//特別提醒:最後的兩個‘>’之間必定要加個空格,不然會被一些編譯器識別爲位運算符「>>」。
q.push(1); //壓入元素1 q.top();//返回此時優先級最高的元素 q.pop();//彈出優先級最高的元素,但不返回它的值 q.empty();//返回一個bool值,若是隊列爲空返回true,不然返回false q.size();//返回隊列中元素的個數
5.1和0既非素數也非合數。
6.通常的篩法(PPT裏叫埃拉託斯特尼篩法,名字異常高貴)的效率是O(NlglgN)(其實很接近O(n)啊!),對於一些例如 N=10000000 的殘暴數據會跪,因而,線性篩登場。
7.a[i]=tolower(a[i]);//大寫轉小寫 a[i]=toupper(a[i]);//小寫轉大寫
8.
if((a%4==0 && a%100!=0)||(a%400==0)) //閏年2月29天 e+=29;
if (a[i]&(1<<j))
這句的意思是判斷 a[i]
的第 j
位是否爲1。 // 1 << x
就是將1左移x位 (bit),好比 1 << 3 == 0b1000
。
sprintf(_d,"%ld",d); //將d轉換爲字符串_d
11.首先在迴文數中,若是位數爲偶數的話,那麼這些迴文數均可以被11整除,如100一、122一、345543都是11的倍數
12.
for (int i=1;i<=n;i++) //從int數組轉化爲數 ,若char數組爲s*10+a[i]-'0'; s=s*10+a[i];
13.
itoa()函數
itoa():char *itoa( int value, char *string,int radix);
原型說明:
value:欲轉換的數據。
string:目標字符串的地址。
radix:轉換後的進制數,能夠是10進制、16進制等,範圍必須在 2-36。
功能:將整數value 轉換成字符串存入string 指向的內存空間 ,radix 爲轉換時所用基數(保存到字符串中的數據的進制基數)。
返回值:函數返回一個指向 str,無錯誤返回。
14.迴文判斷,求出數的逆序,若是逆序跟正序相等,就是迴文數.
bool ispalindrome(int n) //迴文判斷,求出數的逆序,若是逆序跟正序相等,就是迴文數 { int temp,total; temp=n; total=0; if(temp==0) return true; while(temp!=0) { total=total*10+temp%10; temp=temp/10; } if(n==total) return true; else return false; }
15.任何一個數mod(就是%)1都等於0
16.string能夠直接比較字典序大小a>b等等
17.
find會挨個查找set,當到達set.end()時,也就是一個也沒找到,返回end set<int> s; s.find(element) != s.end() // 沒到達end,說明在set中找到element這個元素 map<int,int> mp; mp.find(element) != mp.end() //在mp中找到這個元素
/* 性質1:若是數a、b都能被c整除,那麼它們的和(a+b)或差(a-b)也能被c整除。 性質2:幾個數相乘,若是其中有一個因數能被某一個數整除,那麼它們的積也能被這個數整除。 能被2整除的數,個位上的數能被2整除(偶數都能被2整除),那麼這個數能被2整除 能被3整除的數,各個數位上的數字和能被3整除,那麼這個數能被3整除 能被4整除的數,個位和十位所組成的兩位數能被4整除,那麼這個數能被4整除 能被5整除的數,個位上爲0或5的數都能被5整除,那麼這個數能被5整除 能被6整除的數,各數位上的數字和能被3整除的偶數,若是一個數既能被2整除又能被3整除,那麼這個數能被6整除 能被7整除的數,若一個整數的個位數字截去,再從餘下的數中,減去個位數的2倍,若是差是7的倍數,則原數能被7整除。若是差太大或心算不易看出是否7的倍數,就須要繼續上述「截尾、倍大、相減、驗差」的過程,直到能清楚判斷爲止。例如,判斷133是否7的倍數的過程以下:13-3×2=7,因此133是7的倍數;又例如判斷6139是否7的倍數的過程以下:613-9×2=595 , 59-5×2=49,因此6139是7的倍數,餘類推。 能被8整除的數,一個整數的末3位若能被8整除,則該數必定能被8整除。 能被9整除的數,各個數位上的數字和能被9整除,那麼這個數能被9整除 能被10整除的數,若是一個數既能被2整除又能被5整除,那麼這個數能被10整除(即個位數爲零) 能被11整除的數,奇數位(從左往右數)上的數字和與偶數位上的數字和之差(大數減少數)能被11整除,則該數就能被11整除。 11的倍數檢驗法也可用上述檢查7的「割尾法」處理!過程惟一不一樣的是:倍數不是2而是1! 能被12整除的數,若一個整數能被3和4整除,則這個數能被12整除 能被13整除的數,若一個整數的個位數字截去,再從餘下的數中,加上個位數的4倍,若是差是13的倍數,則原數能被13整除。若是差太大或心算不易看出是否13的倍數,就須要繼續上述「截尾、倍大、相加、驗差」的過程,直到能清楚判斷爲止。 能被17整除的數,若一個整數的個位數字截去,再從餘下的數中,減去個位數的5倍,若是差是17的倍數,則原數能被17整除。若是差太大或心算不易看出是否17的倍數,就須要繼續上述「截尾、倍大、相減、驗差」的過程,直到能清楚判斷爲止。 另外一種方法:若一個整數的末三位與3倍的前面的隔出數的差能被17整除,則這個數能被17整除 能被19整除的數,若一個整數的個位數字截去,再從餘下的數中,加上個位數的2倍,若是差是19的倍數,則原數能被19整除。若是差太大或心算不易看出是否19的倍數,就須要繼續上述「截尾、倍大、相加、驗差」的過程,直到能清楚判斷爲止。 另外一種方法:若一個整數的末三位與7倍的前面的隔出數的差能被19整除,則這個數能被19整除 能被23整除的數,若一個整數的末四位與前面5倍的隔出數的差能被23(或29)整除,則這個數能被23整除 能被25整除的數,十位和個位所組成的兩位數能被25整除。 能被125整除的數,百位、十位和個位所組成的三位數能被125整除。 */
18.
sort複雜度:nlogn 儘可能不用cin
19.coprime "互質"
20. https://www.cnblogs.com/hadilo/p/5914302.html
擴展歐幾里得算法,簡稱 exgcd,通常用來求解不定方程,求解線性同餘方程,求解模的逆元等
引理:存在 x , y 使得 gcd(a,b)=ax+by
21.數據範圍12(很小)。顯然DFS
給你兩個操做,問能不能把數字a變成b。這題大多數一眼看就是dfs
22.
在這些以前都有的前提,那就是真個數組是一個非降序列!!!!!! lower_bound()函數怎麼使用呢?我想這就是不少讀者會遇到的問題,下邊就有小編我來幫你們解釋一下吧,自豪的說幾句大笑。 提及來我用一句話來歸納,就是它的參數就是:一個數組元素的地址(或者數組名來表示這個數組的首地址,用來表示這個數組的開頭比較的元素的地址,不必定要是首地址,只是用於比較的「首」地址),一個數組元素的地址(對應的這個數組裏邊任意一個元素的地址,表示這個二分裏邊的比較的"結尾'地址),再而後就是一個你要二分查找的那個數。 參數說完了,如今說說返回值,返回值就是返回第一次出現大於等於那個要查找的數的地址,注意兩點,第一,是地址,不是指那個要查找的數的下標,因此就註定了在這個函數的後邊就要減去一個尾巴,那就是這個數組的數組名,即這個數組的首地址得意,只有這樣才表明那個要查找的數字的下標,固然若是沒有找到那個數,也是會返回的,那麼返回的又會是什麼呢?疑問;這就是我要講的第二點,那就是要大於等於那個數,等於好理解大笑,大於怎麼理解呢疑問,好比說我並無找到那個數,加入一個的數組裏邊就有5個數,分別是1,1,1,3,5,而我須要找的那個數就是2,怎麼返回呢疑問小編告訴你哦,就是返回那個第一個大於2的數的地址,就是返回3的地址,那麼再有一組數據就是5個數1,1,1,3,3,仍是須要找尋2,那麼該返回什麼呢?小編告訴你哦,那就是第一個3的地址。下邊來段代碼你理解下吧
23.
兩個字符串之間的漢明距離是指兩個相等長度的字符串,對應位置上不一樣字符的個數。
例子以下:
A=abcdef
B=adddef
則A與B之間的漢明距離是2,由於第二位和第三位不一樣。
24.
最近作題的時候,常常遇到範圍是2^63,取模2^64的這種題目。遇到這種限制條件時就要想到用unsigned long long類型。
能夠簡潔地聲明爲typedef unsigned long long ull。這樣,若是ull類型的整數溢出了,就至關於取模2^64了。由於ull的範圍是[0,2^64-1]。
而ll的範圍是[-2^63,2^63-1],由於有符號的第63位表示「正負」而不表示數值。
25.雙指針利用序列的遞增性。
26.容斥原理:通常在集合的個數m比較小,而且並集這些項容易計算時適合使用容斥原理。
27.
substr有2種用法:
假設:string s = "0123456789";
string sub1 = s.substr(5); //只有一個數字5表示從下標爲5開始一直到結尾:sub1 = "56789"
string sub2 = s.substr(5, 3); //從下標爲5開始截取長度爲3位:sub2 = "567"
28.
void dfs(答案,搜索層數,其餘參數){ if(層數==maxdeep){ 更新答案; return; } (剪枝) for(枚舉下一層可能的狀態){ 更新全局變量表示狀態的變量; dfs(答案+新狀態增長的價值,層數+1,其餘參數); 還原全局變量表示狀態的變量; } }
28.%c吃回車
29記憶化搜索:.通常說來,動態規劃總要遍歷全部的狀態,而搜索能夠排除一些無效狀態。更重要的是搜索還能夠剪枝,可能剪去大量沒必要要的狀態,所以在空間開銷上每每比動態規劃要低不少。記憶化算法在求解的時候仍是按着自頂向下的順序,可是每求解一個狀態,就將它的解保存下來,之後再次遇到這個狀態的時候,就沒必要從新求解了。這種方法綜合了搜索和動態規劃兩方面的優勢,於是仍是頗有實用價值的。
30.動態規劃是一種算法,有兩種實現方式:遞推和記憶化搜索
31.計算一個數x的位數是log10(x)+1,計算log10(a^b)+1能夠化爲b*log10(a)+1
32.矩陣快速冪中矩陣的構造技巧
對於出現線性遞推的題目,當直接暴力計算的複雜度過高時,咱們能夠考慮用矩陣快速冪進行加速。
由於雖然矩陣乘法的複雜度爲O(n^3),可是經過二進制分解,總體的複雜度變成了 log(n^3) = 3logn = O(logn),複雜度是對數級別的,很是小。
可是矩陣快速冪的難點就是在如何構造矩陣來完成計算。
由於矩陣快速冪是用來加速線性遞推的,因此最核心的部分就是線性遞推公式。
最經典的就是斐波那契數列的遞推: f(n) = f(n-1) + f(n-2);
其對應的矩陣就是 f(n+1) 1 1 f(n)
f(n) = 0 1 * f(n-1)
能夠發現,左面是個常數矩陣,而右面的列向量中每一項就是遞推公式中的依賴項。
當遞推公式中出現常數時,咱們只需在右面的列向量中加入個常數1,便可。
剩下的就是咱們如何去構造左面的常數矩陣。其實給出了右面的列向量,咱們在根據題中的遞推公式,在左面的常數矩陣中填入對應的常數便可。
這樣,這個問題就圓滿的解答了。
33.
cin>>str; //遇到空格不在寫入 str
getline(cin, str); //遇到回車(換行)不在寫入 str
34.使用typedef目的通常有兩個,一個是給變量一個易記且意義明確的新名字,另外一個是簡化一些比較複雜的類型聲明。
35.須要付出代價而且得到收益,這是揹包問題
36. n - n / k * k = n % k
獲取距離n最近的k的倍數的方法是: n / k * k = n - n % k
37.
if(a>2*b)
a%=2*b(效率高)
a-=2*b(減法太慢)
38.
經過count()和find()查找元素 若是須要判斷某map中是否存在某key的元素,不能經過取下標的方式判斷,由於這樣會使得向map中添加新元素。 map標準庫中提供了兩個判斷key是否存在的方法。 map::count(k),返回map中k出現的次數,爲0固然就表示不存在了。 map::find(k),若是map中存在按k索引的元素,則返回指向該元素的iterator;若是不存在則返回end()
39.
遇到小寫十六進制數轉換成數字時用 好比0x0b應當對應十進制11 若是我拿到字符:'b',將之轉換成11的方法就是 'b'-'a'獲得1,加10獲得11,同理'f'-'a'+10=15
當要把一個字符格式數字轉化爲整型數字時,能夠這樣用: char a = '7' ;
int b = a - '0' ; //b = 7 同理 數字加'0'可轉化爲字符
40. 18446744073709551615 = 2^64 - 1 是unsigned long long能表示的最大的數,輸入輸出用%llu或%I64u。
41.咱們知道f【Fib數列%p】若是出現了連續的1,0就意味這着開始循環了,由於接下來的項就是1 1 2 3 5等等
42.初始化map寫在函數比較好,模塊化
void init() { mp["Weapon"] = 1; mp["Shield"] = 2; mp["Two-Handed"] = 3; mp["Finger"] = 4; mp["Feet"] = 5; mp["Legs"] = 6; mp["Waist"] = 7; mp["Wrist"] = 8; mp["Hand"] = 9; mp["Torso"] = 10; mp["Neck"] = 11; mp["Shoulder"] = 12; mp["Head"] = 13; }
43. upper_bound,功能是在一段單調遞增的序列中找到第一個大於目標元素的地址。用處是能夠統計小於或等於value的元素有多少個(因此要減1)
44.能以規律總結方式作的題,不要同分類討論和模擬作。很容易把問題繁瑣化,形成AC壓力。