1. 程式人生 > 實用技巧 >常見資料結構/演算法模板

常見資料結構/演算法模板


title: 常見資料結構/演算法模板
date: 2020-08-20
categories: acm
tags: acm
top: true

0. to start with

remembering one trick is better than recording a hundred.

包含一些模板和例題

技巧,STL,函式,細節,參考資料(比如揹包九講)等見 https://www.cnblogs.com/lqerio/p/13484897.html

1. DP Dynamic Programming

如果前面的結果可以被利用,就可以dp。
先寫狀態轉移方程,邊界條件,初始結束狀態的設定。
如果資料計算量大可以預處理。

woj1023.
dp 狀態轉移方程: f[i]=min(f[i],f[j]+valuecluser[j+1][i])(i-j>=p)  //j+1...注意分界點 dp[0]=0.i in range p-1-N (編號為1-n)
//dp注意初始狀態結束狀態預處理。f[0]=0,f[i]初始為maxd
預處理:計算valuecluster[i][j]

1.1 Pack 揹包

1.1.1 01揹包

WOJ1005
const int maxn=10005;
int value[maxn];
int sizee[maxn];
int final[100005];
for(int i=0;i<=noah;i++) final[i]=0;  
    for(int i=0;i<n;i++)
        for(int j=noah;j>0;j--)   //倒序理解就是01揹包只有一件,前i-1件已經判斷完了,只判斷這一件,在比較小的情況下放不影響在比較大的情況放
            if(j>=sizee[i])         //final可行因為如果小的能放大的也能放。
                final[j]=max(final[j],final[j-sizee[i]]+value[i]);
        cout<<final[noah]<<endl;
    }

1.2 剪枝 / 回溯

還是待更新!!!!
下面的不全

剪枝
1.最優化剪枝:如果當前已經找到的最優路徑長度為L ,那麼在繼續搜尋的過程中,總長度已經大於等於L的走法,就可以直接放棄,不用走到底了

2.可行性剪枝:如果當前到達城市的路費已大於k,或者等於k且沒有到達終點,就可以直接放棄。

回溯

used[i] = 1;//設為用過 
            dfs(u + 1);//下一個數字 
            used[i] = 0;//回溯:回到沒用過 
			

1.3 方格&&滾動陣列&&優化時間

見我的woj1012題解

2. DFS

2.1 recursive

PAT 1004
#include<iostream>
#include<queue>
#include<vector>

using namespace std;
vector<int>nodes[100];
int ans[105];
int level;
void dfs(int id,int depth){
    level=max(level,depth);
    int temp=id;
        if(nodes[temp].size()==0){
            ans[depth]++;
        }
        else{
            for(int i=0;i<nodes[temp].size();i++){
                dfs(nodes[temp][i],depth+1);
            }
        }
}

int main(){
    int n,m;
    cin>>n>>m;
    int father,num,son;
    for(int i=0;i<m;i++){
        cin>>father>>num;
        for(int j=0;j<num;j++){
            cin>>son;
            nodes[father].push_back(son); // at first i write push_back[]
        }
    }
    level=1;
    dfs(1,level);
    cout<<ans[1];
    for(int i=2;i<=level;i++) //at first i write push_back[] < but not <=
        cout<<' '<<ans[i];
        system("pause");
    return 0;
}

2.2 stack

找到與最先出發點的所有鄰接點,將他們入棧,
標記這些點已經訪問過,後面和bfs的佇列實現有點像。
UVA280

#include<bits/stdc++.h>
using namespace std;
const int maxn=150;
int node_num,st,ed,stnodenum,stnode,vis[maxn];
 
void dfs(int stnode,vector<int> v[]){
    memset(vis,0,sizeof(vis));
    stack<int> s;
    vector<int> t;
    for(int i=0;i<v[stnode].size();i++){
        int temp=v[stnode][i];
        if(!vis[temp]){
            s.push(temp);
            vis[temp]=1;
        }
    }
    while(!s.empty()){
        int ans=s.top();
        s.pop();
        for(int i=0;i<v[ans].size();i++){
            int temp=v[ans][i];
            if(!vis[temp]){
                s.push(temp);
                vis[temp]=1;
            }
        }
    }
    for(int i=1;i<=node_num;i++){
        if(!vis[i])
        t.push_back(i);
    }
    cout<<t.size();
    for(int i=0;i<t.size();i++)
        cout<<" "<<t[i];
    cout<<endl;
}
 
int main(){
    while(scanf("%d",&node_num)!=EOF){
        if(node_num==0) break;
        vector<int> v[maxn];
        for(;;){
            scanf("%d",&st);
            if(!st)
                break;
            for(;;){
                scanf("%d",&ed);
                if(!ed)
                    break;
                v[st].push_back(ed);
            }
        }
        scanf("%d",&stnodenum);
        for(int i=0;i<stnodenum;i++){
            scanf("%d",&stnode);
            dfs(stnode,v);
        }
    }
    return 0;

3. BFS

3.1 QUEUE

PAT 1004
#include<iostream>
#include<queue>
#include<vector>

using namespace std;
vector<int>nodes[100];
int ans[105];
int depth[105];
int level;
void bfs(int id){
    queue<int>q;
    q.push(id);
    while(!q.empty()){
        int temp=q.front(); //at first i write "top()"
        q.pop();
        level=max(level,depth[temp]);
        if(nodes[temp].size()==0){
            ans[depth[temp]]++;
        }
        else{
            for(int i=0;i<nodes[temp].size();i++){
                depth[nodes[temp][i]]=depth[temp]+1;
                q.push(nodes[temp][i]);
            }
        }
        
    }
}

int main(){
    int n,m;
    cin>>n>>m;
    int father,num,son;
    for(int i=0;i<m;i++){
        cin>>father>>num;
        for(int j=0;j<num;j++){
            cin>>son;
            nodes[father].push_back(son); // at first i write push_back[]
        }
    }
    depth[1]=1;
    level=1;
    bfs(1);
    cout<<ans[1];
    for(int i=2;i<=level;i++) //at first i write push_back[] < but not <=
        cout<<' '<<ans[i];
        system("pause");
    return 0;
}

3.2 recursion

void BFS(int st) {
	int len = G[st].size();
	for (int i = 0 ; i < len ; i ++ ) {
		que.push(G[st][i]);
	}
	if ( !que.empty() ) {
		int top = que.front() ; que.pop() ;
		printf("%d ",top) ;
		BFS(top) ;
	}

4. topo 拓撲排序

//拓撲排序可以判斷有向圖有沒有環。
//dfs判斷圖聯通。

5. math

5.1 euler path /circuit

https://www.cnblogs.com/wkfvawl/p/9626163.html

DFS Fleury(佛羅萊)演算法求解

5.2 Huffman Coding 哈夫曼編碼

6. GRAPH 圖

6.1 Red Black Tree

6.2 AVL

6.3 tree traversal 樹的遍歷

https://www.cnblogs.com/qjmnong/p/9135386.html

Pre-order

recursive

void pre_order(TreeNode * Node)
{
if(Node == NULL)
return;
printf("%d ", Node->data);
pre_order(Node->left);
pre_order(Node->right);
}

Iteration

class TreeNode {
	public int val;
	public TreeNode left, right;

	public TreeNode(int val) {
		this.val = val;
		this.left = this.right = null;
	}
}

先push(root)
node = pop()
loop:
list.add( node.val )
push( node.right )
push( node.left )
迴圈步驟直到棧空

public List<Integer> preorderTraversal(TreeNode root) {
		if (root == null) {
			return null;
		}
		List<Integer> list = new ArrayList<Integer>();

		Stack<TreeNode> s = new Stack<TreeNode>();
		s.push(root);

		while (!s.isEmpty()) {
			
			TreeNode node = s.pop();
			list.add(node.val);
			
			if (node.right != null) {
				s.push(node.right);
			}
			
			if (node.left != null) {
				s.push(node.left);
			}
		}
		
		return list;
	}

Middle-order

recursive

void middle_order(TreeNode *Node)//中序遍歷遞迴演算法
{
    if(Node == NULL)
        return;
    middle_order(Node->left);
    printf("%d ", Node->data);//在中間
    middle_order(Node->right);
}

Iteration

把root、以及root左孩子都壓入棧中
loop:
node = pop()
list.add( node.val )
root = node.right
迴圈步驟直到棧為空且root為null

public static List<Integer> inorderTraversal(TreeNode root) {
		if (root == null) {
			return null;
		}
		List<Integer> list = new ArrayList<Integer>();

		Stack<TreeNode> s = new Stack<TreeNode>();

		do {
			while (root != null) {
				s.push(root);
				root = root.left;
			}
			if (!s.isEmpty()) {
				TreeNode node = s.pop();
				list.add(node.val);
				root = node.right;
			}
		} while (!s.isEmpty() || root != null);

		return list;
	}

Post-order

recursive

void post_order(TreeNode *Node)//後序遍歷遞迴演算法
{
    if(Node == NULL)
        return; 
    post_order(Node->left);
    post_order(Node->right);
    printf("%d ", Node->data);//在最後
}

Iteration

先push(root)
loop:
node = pop()
list.add( 0 , node.val )
push( node.left )
push( node.right )
迴圈步驟3直到棧空
之後倒序遍歷list

public static List<Integer> postorderTraversal(TreeNode root) {
		if (root == null) {
			return null;
		}
		List<Integer> list = new ArrayList<Integer>();

		Stack<TreeNode> s = new Stack<TreeNode>();
		
		s.push(root);
		
		while( !s.isEmpty() ) {
			TreeNode node = s.pop();
			if(node.left != null) {
				s.push(node.left);
			}
			
			if(node.right != null) {
				s.push(node.right);
			}
			
			list.add(0, node.val);
		}
		
		return list;
	}

6.4 BST (binary search tree)

https://www.cnblogs.com/lqerio/p/11901828.html

6.5 最短路

https://blog.csdn.net/strve/article/details/80957491
Floyed +Dijkstra + Bellman-Ford + SPFA (SPFA就是佇列優化版的BF)。
///BF 適用於含有負邊的圖。如果有負邊,返回false。Dijkstra演算法無法判斷含負權邊的圖的最短路.二者都適用於有向有環圖。
//拓撲排序可以判斷有向圖有沒有環。
//dfs判斷圖聯通。

6.5.1 dijkstra

PAT 1003 為例

模板 Dijkstra+鏈式前向星+堆優化

https://www.cnblogs.com/zmin/p/7349100.html

matrix O() 鄰接矩陣版

#include<bits/stdc++.h>
using namespace std;
int graph[505][505];//圖
int city[505],dis[505],pathNum[505],teamNum[505];//每個城市救護隊的數量、到達每個城市的最短距離、到達每個城市的最短路徑的數量、到達每個城市的救護隊數量
bool visit[505];//每個城市是否被訪問過
int N,M,C1,C2;
void Dijkstra(){
    while(!visit[C2]){//如果終點城市還沒有被訪問,繼續迴圈
        int MIN=INT_MAX,v=-1;//找出目前距離最短的還沒有被訪問的城市
        for(int i=0;i<N;++i)
            if(!visit[i]&&MIN>dis[i]){
                MIN=dis[i];
                v=i;
            }
        visit[v]=true;//標記為已訪問
        for(int i=0;i<N;++i)
            if(!visit[i]&&graph[v][i]!=0&&dis[v]+graph[v][i]<dis[i]){
                dis[i]=dis[v]+graph[v][i];//更新最短路徑長度
                pathNum[i]=pathNum[v];//更新最短路徑數量
                teamNum[i]=teamNum[v]+city[i];//更新城市的救護隊數量
            }else if(graph[v][i]!=0&&dis[v]+graph[v][i]==dis[i]){
                pathNum[i]+=pathNum[v];//增加最短路徑數量
                teamNum[i]=max(teamNum[i],teamNum[v]+city[i]);//找出能夠召集最多的城市救護隊數量
            }
    }
}
int main(){
    scanf("%d%d%d%d",&N,&M,&C1,&C2);
    for(int i=0;i<N;++i)
        scanf("%d",&city[i]);
    while(M--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        graph[a][b]=c;
        graph[b][a]=c;
    }
    fill(dis,dis+N,INT_MAX);//將最短路徑均設定為最大值
    dis[C1]=0;//C1城市是起點,最短路徑為0
    teamNum[C1]=city[C1];//C1城市是起點,最短路徑數量為1
    pathNum[C1]=1;//C1城市是起點,能夠召集的救護隊數量為本城市的數量
    Dijkstra();
    printf("%d %d",pathNum[C2],teamNum[C2]);//輸出
    return 0;
}

鄰接表版

#include<bits/stdc++.h>
using namespace std;
struct Road{
    int v;//道路盡頭的城市編號
    int length;//道路長度
    Road(int vv=0,int l=0):v(vv),length(l){}
};
vector<vector<Road>>graph(505);//圖
int city[505],dis[505],pathNum[505],teamNum[505];//每個城市救護隊的數量、到達每個城市的最短距離、到達每個城市的最短路徑的數量、到達每個城市的救護隊數量
bool visit[505];//每個城市是否被訪問過
int N,M,C1,C2;
void Dijkstra(){
    while(!visit[C2]){//如果終點城市還沒有被訪問,繼續迴圈
        int MIN=INT_MAX,v=-1;//找出目前距離最短的還沒有被訪問的城市
        for(int i=0;i<N;++i)
            if(!visit[i]&&dis[i]<MIN){
                MIN=dis[i];
                v=i;
            }
        visit[v]=true;//標記為已訪問
        for(Road r:graph[v]){
            if(!visit[r.v]&&dis[r.v]>dis[v]+r.length){
                dis[r.v]=dis[v]+r.length;//更新最短路徑長度
                pathNum[r.v]=pathNum[v];//更新最短路徑數量
                teamNum[r.v]=teamNum[v]+city[r.v];//更新城市的救護隊數量
            }else if(dis[r.v]==dis[v]+r.length){
                pathNum[r.v]+=pathNum[v];//增加最短路徑數量
                teamNum[r.v]=max(teamNum[r.v],teamNum[v]+city[r.v]);//找出能夠召集最多的城市救護隊數量
            }
        }
    }
}
int main(){
    scanf("%d%d%d%d",&N,&M,&C1,&C2);
    for(int i=0;i<N;++i)
        scanf("%d",&city[i]);
    while(M--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        graph[a].push_back(Road(b,c));
        graph[b].push_back(Road(a,c));
    }
    fill(dis,dis+N,INT_MAX);//將最短路徑均設定為最大值
    dis[C1]=0;//C1城市是起點,最短路徑為0
    pathNum[C1]=1;//C1城市是起點,最短路徑數量為1
    teamNum[C1]=city[C1];//C1城市是起點,能夠召集的救護隊數量為本城市的數量
    Dijkstra();
    printf("%d %d",pathNum[C2],teamNum[C2]);//輸出
    return 0;
}

priority_queue lrj版

設m edges,n vertexs
複雜度 mlog(n)
演算法中 ** while(!Q.empty()){} ** 部分使得每個邊都被遍歷到,m。而優先佇列插入複雜度為log(n).故整體mlog(n)
注意m可能大於n^2 最後複雜的>n^2.但不常見

PAT 1003

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include<vector>

using namespace std;
const int maxn = 505 + 5; //vertexs
const int INF = 99999999;

int city[505];
int pathnum[505],teamnum[505];

struct Edge
{
    int from,to,dist;
    Edge(int f=0,int t=0,int d=0):from(f),to(t),dist(d){}
};
struct HeapNode//優先佇列節點
{
    int d,u;
    HeapNode(int _d=0,int _u=0):d(_d),u(_u){}
    bool operator<(const HeapNode &rhs)const
    {
        return d>rhs.d;
    }
};
struct Dijkstra  //邊權為正 負權存在用Bellman-Ford 每兩點間最短路floyd
{
    int n,m;               //點數和邊數  O(mlog n)
    vector<Edge> edges;    //邊列表
    vector<int> G[maxn];   //每個節點出發的邊編號(編號從0開始)
    bool done[maxn];       //是否已永久標號
    int d[maxn];           //s到各個點的距離
    int p[maxn];           //最短路中的上一條邊
    void init(int n)
    {
        this->n=n;
        for(int i=0;i<n;i++)G[i].clear();
        edges.clear();
    }
    void AddEdge(int from,int to,int dist)
    {
        edges.push_back(Edge(from,to,dist));
        m=edges.size();
        G[from].push_back(m-1);
        
                edges.push_back(Edge(to,from,dist)); //無向圖,雙向
        m=edges.size();
        G[to].push_back(m-1);
    }

    void dijkstra(int s)   //s start
    {
        priority_queue<HeapNode> Q;   //優先佇列,d[i]越小越先出隊
        for(int i=0;i<n;i++)d[i]=INF;
        d[s]=0;
        memset(done,0,sizeof(done));
        Q.push(HeapNode(0,s));
        while(!Q.empty()) //第一輪將s能到的點都壓入佇列,之後每次取d[i]最小的點先出(優先佇列)
        {
            HeapNode x=Q.top();Q.pop();
            int u=x.u;                     //u 當前處理點編號
            if(done[u])continue;
            done[u]=true;
            for(int i=0;i<G[u].size();i++)
            {
                Edge &e=edges[G[u][i]];
                if(d[e.to]>d[u]+e.dist)
                {
                    d[e.to]=d[u]+e.dist; //d[u],出發點s到u的距離
                    p[e.to]=G[u][i];     //到達e.to點的邊為G[u][i]
                    Q.push(HeapNode(d[e.to],e.to));
                        pathnum[e.to]=pathnum[e.from];
                        teamnum[e.to]=city[e.to]+teamnum[e.from];
                }
                else if(d[e.to]==d[u]+e.dist){
                         pathnum[e.to]+=pathnum[e.from];
                        teamnum[e.to]=max(city[e.to]+teamnum[e.from],teamnum[e.to]);
                }
            }
        }
    }
};

int main()
{
    Dijkstra dijk;
    int n,m,start,end;                 //n number of vertex m number of edges
    cin>>n>>m>>start>>end;
    for(int i=0;i<n;i++)
        cin>>city[i];
        dijk.init(n);
        int from,to,dist;
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d",&from,&to,&dist);
            dijk.AddEdge(from,to,dist);
        }
    pathnum[start]=1;
    teamnum[start]=city[start];
    dijk.dijkstra(start);
    cout<<pathnum[end]<<' '<<teamnum[end];
    
    return 0;
}

6.5.2 SPFA

woj1009

// woj1009

#define INF 0x3f3f3f3f


char word[4005];
int plovers,slovers;
int n, m,edgenum;
const int maxn=105;  //const    點的數

struct Edge {
int from, to, power,speed,dist;
char word;
Edge(int u, int v,int p,int s, int d,char word):from(u),to(v),power(p),speed(s),dist(d),word(word){}
};

vector<Edge> edges;
vector<int> G[maxn];
bool inq[maxn]; //是否在佇列裡
int d[maxn]; //s到各個點的距離
int p[maxn]; //最短路中的上一條弧
int cnt[maxn]; //入隊次數 次數大於n則說明有負環

void init(int n) {
edgenum=0;
for(int i = 0; i < n; i++) G[i].clear();
edges.clear();
}

void AddEdge(int from, int to, int power,int speed,int dist,char word) {
edges.push_back(Edge(from, to, power,speed,dist,word));
edgenum = edges.size();           //錯誤,一開始寫成m,而m又是全域性變數導致下面data()的迴圈除了問題
G[from].push_back(edgenum-1);  //邊的標號
}

//拓撲排序可以判斷有向圖有沒有環
//dfs判斷圖聯通

bool bellman_ford(int s) {  ///BF 適用於含有負邊的圖。如果有負邊,返回false。Dijkstra演算法無法判斷含負權邊的圖的最短路.二者都適用於有向有環圖
    queue<int> Q;
    memset(inq, 0, sizeof(inq));
    memset(cnt, 0, sizeof(cnt));
    for(int i = 0; i < n; i++) d[i] = INF;
    d[s] = 0;
    inq[s] = true;
    p[s]=-1;     //加了一條
    Q.push(s);
    while(!Q.empty()) {
        int u = Q.front(); Q.pop();
        inq[u] = false;
        for(int i = 0; i < G[u].size(); i++) {
            Edge& e = edges[G[u][i]];
                if(d[u] < INF && d[e.to] > d[u] + e.dist&&plovers>e.power&&slovers>e.speed) {    //模板,+條件
                    d[e.to] = d[u] + e.dist;
                    p[e.to] = G[u][i];
                    if(!inq[e.to]) { Q.push(e.to); inq[e.to] = true; if(++cnt[e.to] > n) return false;}
                }
        }
    }
    vector<char>ans;  //也可以寫一個函式遞迴,沒必要
    int tmp=p[n-1];
    while(tmp!=-1){
        ans.push_back(edges[tmp].word);
        tmp=p[edges[tmp].from];
    }
    for(int i=ans.size()-1;i>-1;i--)
        cout<<ans[i];
    cout<<endl;
    return true;
}


void data(){
    init(n);
    int from,to,power,speed,dist,tmp;
    char word;
    for(int i=0;i<m;i++){
        /*  這樣寫有問題。讀了空格
           scanf("%d%d%d%d%d",&from,&to,&power,&speed,&dist);
           scanf("%c",&word);
           */
          /*
          scanf("%d%d%d%d%d",&from,&to,&power,&speed,&dist);
           getchar();scanf("%c",&word);getchar();*/     //處理最後一個字元前的空格這樣可以,但是麻煩
           scanf("%d %d %d %d %d %c",&from,&to,&power,&speed,&dist,&word);  //注意%c不是%s 。也可以fstream
           AddEdge(from,to,power,speed,dist,word);
           }
    cin>>plovers>>slovers;
    bellman_ford(0);
}


6.6 生成樹

6.7 如何建圖?

鄰接矩陣  //資料範圍很大,不能用鄰接矩陣

鄰接表

鄰接表可以用 連結串列或者 vector 見 woj1006

vector<int>mapp;
for(int i=0;i<n;i++)
            mapp[i].clear();
        for(int i=0;i<m;i++){
            scanf("%d%d", &x, &y);  mapp[x].push_back(y);  mapp[y].push_back(x);
        }


紫書模板建圖 見我的題解 woj1009


一般的用vector[i]表示i所連邊 見我的題解 woj1024

7. Sort

https://www.cnblogs.com/lqerio/p/13484897.html

8. greedy 貪心

https://www.cnblogs.com/lqerio/p/11749926.html

9. 字串 string

9.1 KMP

9.2 AC 自動機

9.3 字典序 Dictionary order

https://www.cnblogs.com/lqerio/p/11785894.html

sort,strcmp,string

woj1013
字典序全排列生成:https://www.cnblogs.com/lqerio/p/12079873.html

比較可以用sort(qsort不推薦)
bool cmp(char*a,char*b){
    return strcmp(a,b);
}

bool cmp1(string a,string b){
    return a<b;
}
vector<string>ans;
sort(ans.begin(),ans.end(),cmp1);

9.4 leetcode5 Manacher法 最長迴文字串

https://www.cnblogs.com/lqerio/p/11723652.html

10. 網路流

見woj1008.

11. kth biggest/smallest

https://www.cnblogs.com/lqerio/p/9757284.html

12. others

12.1 make an structure of O(1) search,insert,delete

leetcode381

12.2 GCD

    int gcd(int a,int b)
    {
       // return (b==0)?gcd(b,a%b):a
         if(b==0)
              return a;
         else
              return gcd(b,a%b);
    }

12.3 Prime

bool isPrime(int n) {

	if (n < 2)
		return false;
   int m=sqrt(n+0.5);
	for (int i = 2; i <= m; i++) {

		if (n % i == 0)
			return false;
	}

	return true;
}

void euler_sieve(int n)  //線性篩
{
    totPrimes = 0;
    memset(flag, 0, sizeof(flag));

    for (int i = 2; i <= n; i++) {
        if (!flag[i])
            primes[totPrimes++] = i;
        for (int j = 0; i * primes[j] <= n; j++) {
            flag[i*primes[j]] = true;
            if (i % primes[j] == 0)
                break;
        }
    }
}

void eratosthenes_sieve(int n)
{
    totPrimes = 0;
    memset(flag, 0, sizeof(flag));

    int sqrtn = sqrt(n + 0.5);
    for (int i = 2; i <= sqrtn; i++) {
        if (!flag[i]) {
            primes[totPrimes++] = i;
            for (int j = i * i; j <= n; j += i) {
                flag[j] = true;
            }
        }
    }
    for (int i = sqrtn + 1; i <= n; i++) {
        if (!flag[i])
            primes[++totPrimes] = i;
    }
}
int binarysearch(int x)
{
    int l=0,r=n*n;
    while(r-l>=1)
    {
        int i=(r+l)/2;
        if(num[i]==x) return 1;
        else if(num[i]<x) l=i+1;
        else r=i;
    }
    return 0;
}

12.5 pow

ll pow(ll a,ll n) //a^n
{
    ll result=1,flag=a;
    while(n!=0)
    {
        if(n&1)
            result=result*flag;
        flag=flag*flag;
        n=n>>1;
    }
    return result;
}

ll pow(ll a,ll n,ll b) //a^n %b  to avoid Integer overflow
{
    ll result=1;
    a=a%b;
    while(n>0)
    {
        if(n%2==1)
            result=result*a%b;
        n=n/2;
        a=a*a%b;
    }
    return result;
}

12.6 floating numbers

uva11809
https://blog.csdn.net/crazysillynerd/article/details/43339157


#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
 
using namespace std;
 
int main() {
    double M[20][40];
    long long E[20][40];
 
    // 打表
    for(int i = 0; i <= 9; ++i) for(int j = 1; j <= 30; ++j) {
        double m = 1 - pow(2, -1 - i), e = pow(2, j) - 1;
        double t = log10(m) + e * log10(2);
        E[i][j] = t, M[i][j] = pow(10, t - E[i][j]);
    }
 
    // 輸入並輸出結果
    string in;
    while(cin >> in && in != "0e0") {
        // 處理輸入
        for(string::iterator i = in.begin(); i != in.end(); ++i) if(*i == 'e') *i = ' ';
        istringstream ss(in);
        double A; int B;
        ss >> A >> B;
        while(A < 1) A *= 10, B -= 1;
        // 在打好的表中尋找答案
        for(int i = 0; i <= 9; ++i) for(int j = 1; j <= 30; ++j) {
            if(B == E[i][j] && (fabs(A - M[i][j]) < 1e-4 || fabs(A / 10 - M[i][j]) < 1e-4)) {
                cout << i << ' ' << j << endl;
                break;
            }
        }
    }
}

12.7 high accuracy

https://www.cnblogs.com/ECJTUACM-873284962/p/6509429.html
uva 1828 fibonacci
https://www.xuebuyuan.com/1888279.html

#include <iostream>
#include <string.h>

using namespace std;

int f[5010][1010];       //第1個5010用來存5010個斐波那契數(測試可知第5000項已超過了1000位),第2個1010表示給每個斐波那契數開1010位

int main()
{
    int i, j;

    memset(f, 0, sizeof(f));

    f[1][0] = 1;        //給第1個斐波那契數置數
    f[2][0] = 1;        //給第2個斐波那契數置數

    for(i = 3; i < 5010; i++)      //從第3項開始,用前2項相加
    {
        int C = 0;      //C表示進位,開始設為0
        for(j = 0; j < 1001; j++)
        {
            f[i][j] = (f[i-2][j] + f[i-1][j] + C) % 10;     //%10後就是這一位該有的數字
            C = (f[i-2][j] + f[i-1][j] + C) / 10;       //相加產生的進位
        }

    }

    int a;
    while(cin>>a)
    {
        for(j = 1001; j >= 0; j--)      //尋找最高位
            if(f[a][j] != 0)
                break;
        for(; j >= 0; j--)
            cout<<f[a][j];
        cout<<endl;
    }
    return 0;
}

https://www.cnblogs.com/lqerio/p/11117608.html

12.9 c++ stl

https://www.cnblogs.com/lqerio/p/13484897.html
https://www.cnblogs.com/lqerio/p/11117601.html

12.10 滑動視窗 Sliding window

https://www.cnblogs.com/lqerio/p/11708680.html
https://www.cnblogs.com/lqerio/p/9741044.html

12.11 雙指標...三指標... two-pointer

https://www.cnblogs.com/lqerio/p/11755868.html