ACM算法模板 · 一些常用的算法模板-模板合集(稍加修改)

 原博客 https://blog.youkuaiyun.com/qq_32265245/article/details/53046750

 

附: 星期数计算模板

int week(int n,int y,int r)
{
    //用来特判闰年
    if( y ==1 || y==2)
    {
        y = y+12;
        n --;
    }
    int ans = (r+2*y+3*(y+1)/5+n+n/4-n/100+n/400)%7;
    return ans+1;
}

 

0.头文件

 

#define _CRT_SECURE_NO_DEPRECATE
#include <set>  
#include <cmath>  
#include <queue>  
#include <stack>  
#include <vector>  
#include <string>  
#include <cstdio>  
#include <cstdlib>  
#include <cstring>  
#include <iostream>  
#include <algorithm>  
#include <functional>  
#include<string.h>  
#include<stdio.h>  
using namespace std;  
  
const int maxn = 110;  
const int INF = 0x3f3f3f3f;  

 

 

 

经典

1.埃拉托斯特尼筛法(求素数)

/*
    |埃式筛法|
    |快速筛选素数|
    |16/11/05ztx|
*/
int qwq[10005]; //这个数组用来存找到的素数
int cnt=0;
int prime[maxn];
bool is_prime[maxn];

int sieve(int n){
    int p = 0;
    for(int i = 0; i <= n; ++i)
        is_prime[i] = true;
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i <= n; ++i){   //  注意数组大小是n
        if(is_prime[i]){
            prime[p++] = i;
            qwq[cnt]=i; cnt++;  //开始存
            for(int j = i + i; j <= n; j += i)  //  轻剪枝,j必定是i的倍数
                is_prime[j] = false;
        }
    }
    return p;   //  返回素数个数
}


int main()
{
    cout<<sieve(100)<<endl;  //输出100内的素数个数,紧接着输出
    for(int i=0;i<cnt;i++) cout<<qwq[i]<<" ";
}

 

 

2.快速幂

 

 

/*
    |快速幂| 传入的分别是x的n次方 并取余m
*/


long long  qwq(long long x, long long  n, long long m)
{
    long long res = 1;
    while (n > 0){
        if  (n & 1) //  判断是否为奇数,若是则true  
            res = (res * x) % m;
        x = (x * x) % m;
        n >>= 1;    //  相当于n /= 2; 
    }
    return res;
}

 

3.大数模拟

 

大数加法

/*
    |大数模拟加法|
    |用string模拟|
    |16/11/05ztx, thanks to caojiji|
*/

string add1(string s1, string s2)
{
    if (s1 == "" && s2 == "")   return "0";
    if (s1 == "")   return s2;
    if (s2 == "")   return s1;
    string maxx = s1, minn = s2;
    if (s1.length() < s2.length()){
        maxx = s2;
        minn = s1;
    }
    int a = maxx.length() - 1, b = minn.length() - 1;
    for (int i = b; i >= 0; --i){
        maxx[a--] += minn[i] - '0'; //  a一直在减 , 额外还要减个'0'
    }
    for (int i = maxx.length()-1; i > 0;--i){
        if (maxx[i] > '9'){
            maxx[i] -= 10;//注意这个是减10
            maxx[i - 1]++;
        }
    }
    if (maxx[0] > '9'){
        maxx[0] -= 10;
        maxx = '1' + maxx;
    }
    return maxx;
}

 

大数阶乘

 

/*
    |大数模拟阶乘|
    |用数组模拟|
    |16/12/02ztx|
*/

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long LL;

const int maxn = 100010;

int num[maxn], len;

/*
    在mult函数中,形参部分:len每次调用函数都会发生改变,n表示每次要乘以的数,最终返回的是结果的长度
    tip: 阶乘都是先求之前的(n-1)!来求n!
    初始化Init函数很重要,不要落下
*/

void Init() {
    len = 1;
    num[0] = 1;
}

int mult(int num[], int len, int n) {
    LL tmp = 0;
    for(LL i = 0; i < len; ++i) {
         tmp = tmp + num[i] * n;    //从最低位开始,等号左边的tmp表示当前位,右边的tmp表示进位(之前进的位)
         num[i] = tmp % 10; //  保存在对应的数组位置,即去掉进位后的一位数
         tmp = tmp / 10;    //  取整用于再次循环,与n和下一个位置的乘积相加
    }
    while(tmp) {    //  之后的进位处理
         num[len++] = tmp % 10;
         tmp = tmp / 10;
    }
    return len;
}

int main() {
    Init();
    int n;
    n = 1977; // 求的阶乘数
    for(int i = 2; i <= n; ++i) {
        len = mult(num, len, i);
    }
    for(int i = len - 1; i >= 0; --i)
        printf("%d",num[i]);    //  从最高位依次输出,数据比较多采用printf输出
    printf("\n");
    return 0;
}

 

4.GCD(求最大公约数)

 

/*
    |辗转相除法|
    |欧几里得算法|
    |求最大公约数|
    |16/11/05ztx|
*/

int gcd(int big, int small)
{
    if (small > big) swap(big, small);
    int temp;
    while (small != 0){ //  辗转相除法
        if (small > big) swap(big, small);
        temp = big % small;
        big = small;
        small = temp;
    }
    return(big);
}

 

5.LCM(求最小公倍数)

 

int n,m;
int LCM(int big, int small)
{
    if (small > big) swap(big, small);
    int temp;
    while (small != 0){ //  辗转相除法
        if (small > big) swap(big, small);
        temp = big % small;
        big = small;
        small = temp;
    }
    return(n*m/big);
}
int main()
{
    cin>>n>>m;
    cout<<LCM(n,m);
}

 

 

6.全排列

 

 

#include<bits/stdc++.h>
using namespace std;

//k是开始的元素标号,n是开始的元素标号+要排列的元素数
//这个规则和sort类似
//若只对a[1]到a[4]进行全排列 则k=1,n=5;
//排列a[0]到a[4],则k=0,n=5
void Pern(int list[], int k, int n)
{   //  k表示前k个数不动仅移动后面n-k位数
    if (k == n - 1) {
        for (int i = 0; i < n; i++) {
            printf("%d", list[i]);
        }
        printf("\n");
    }else {
        for (int i = k; i < n; i++) {   //  输出的是满足移动条件所有全排列
            swap(list[k], list[i]);
            Pern(list, k + 1, n);
            swap(list[k], list[i]);
        }
    }
}

int main()
{
    int qwq[10]={1,2,3,4,5};
    Pern(qwq,0,5);
}

 

7.二分搜索

 

#include<bits/stdc++.h>
using namespace std;

//二分查找 arr是数组名,len是长度,key是要查找的数
//查到则返回元素下标 查不到返回-1
int binarySearch(int arr[], int len, int key)
{
    int left = 0;
    int right = len - 1;
    int mid;

    while (left <= right) {
        mid = (left + right) / 2;
        if (key < arr[mid]) {//key在左边
            right = mid - 1;
        } else if (arr[mid] < key) {//key在右边
            left = mid + 1;
        } else {
            return mid;
        }
    }
    return -1;
}

int main()
{
    int qwq[5]={1,5,22,132,133};
    //在长度为5的qwq数组中查找22
    cout<<binarySearch(qwq,5,22);

}

 

数据结构

 

并查集

8.并查集

int father[10005];
void inti()
{
    //初始化 father[i] = i;
}
//递归写法
int findd(int x)
{
    if(father[x] == x) return x;
    else
    {
        father[x] = findd(father[x]);
        return father[x];
    }
}
//迭代写法
/*
int findd(int x) {   //  迭代找根节点
    int root = x; // 根节点
    while (root != father[root]) { // 寻找根节点
        root = father[root];
    }
    while (x != root) {
        int tmp = father[x];
        father[x] = root; // 根节点赋值
        x = tmp;
    }
    return root;
}
*/
void join(int x,int y)
{
    int fx = findd(x);
    int fy = findd(y);
    if(fx != fy) father[fy] = fx;
}

 

图论

 

MST

最小生成树

Kruskal

9.克鲁斯卡尔算法

/*
    |Kruskal算法|
    |适用于 稀疏图 求最小生成树|
    |16/11/05ztx thanks to wangqiqi|
*/

/*
    第一步:点、边、加入vector,把所有边按从小到大排序
    第二步:并查集部分 + 下面的code
*/

void Kruskal() {    
    ans = 0;    
    for (int i = 0; i<len; i++) {    
        if (Find(edge[i].a) != Find(edge[i].b)) {    
            Union(edge[i].a, edge[i].b);    
            ans += edge[i].len;    
        }    
    }    
}    

 

  •  

 

Prim

10.普里姆算法

/*
    |Prim算法|
    |适用于 稠密图 求最小生成树|
    |堆优化版,时间复杂度:O(elgn)|
    |16/11/05ztx, thanks to chaixiaojun|
*/

struct node {  
    int v, len;  
    node(int v = 0, int len = 0) :v(v), len(len) {}  
    bool operator < (const node &a)const {  // 加入队列的元素自动按距离从小到大排序  
        return len> a.len;  
    }  
};

vector<node> G[maxn];
int vis[maxn];
int dis[maxn];

void init() {  
    for (int i = 0; i<maxn; i++) {  
        G[i].clear();  
        dis[i] = INF;  
        vis[i] = false;  
    }  
}  
int Prim(int s) {  
    priority_queue<node>Q; // 定义优先队列  
    int ans = 0;  
    Q.push(node(s,0));  // 起点加入队列  
    while (!Q.empty()) {   
        node now = Q.top(); Q.pop();  // 取出距离最小的点  
        int v = now.v;  
        if (vis[v]) continue;  // 同一个节点,可能会推入2次或2次以上队列,这样第一个被标记后,剩下的需要直接跳过。  
        vis[v] = true;  // 标记一下  
        ans += now.len;  
        for (int i = 0; i<G[v].size(); i++) {  // 开始更新  
            int v2 = G[v][i].v;  
            int len = G[v][i].len;  
            if (!vis[v2] && dis[v2] > len) {   
                dis[v2] = len;  
                Q.push(node(v2, dis[v2]));  // 更新的点加入队列并排序  
            }  
        }  
    }  
    return ans; 
}  
#include<iostream>
#include<string>
#include<vector>
using  namespace std;

//首先是使用邻接矩阵完成Prim算法
struct Graph {
    int vexnum;  //顶点个数
    int edge;   //边的条数
    int ** arc; //邻接矩阵
    string *information; //记录每个顶点名称
};

//创建图
void createGraph(Graph & g) {
    cout << "请输入顶点数:输入边的条数" << endl;
    cin >> g.vexnum;
    cin >> g.edge;  //输入边的条数

    g.information = new string[g.vexnum];
    g.arc = new int*[g.vexnum];
    int i = 0;

    //开辟空间的同时,进行名称的初始化
    for (i = 0; i < g.vexnum; i++) {
        g.arc[i] = new int[g.vexnum];
        g.information[i]="v"+ std::to_string(i+1);//对每个顶点进行命名
        for (int k = 0; k < g.vexnum; k++) {
            g.arc[i][k] = INT_MAX;          //初始化我们的邻接矩阵
        }
    }

    cout << "请输入每条边之间的顶点编号(顶点编号从1开始),以及该边的权重:" << endl;
    for (i = 0; i < g.edge; i++) {
        int start;
        int end;
        cin >> start;   //输入每条边的起点
        cin >> end;     //输入每条边的终点
        int weight;
        cin >> weight;
        g.arc[start-1][end-1]=weight;//无向图的边是相反的
        g.arc[end-1][start-1] = weight;
    }
}

//打印图
void print(Graph g) {
    int i;
    for (i = 0; i < g.vexnum; i++) {
        //cout << g.information[i] << " ";
        for (int j = 0; j < g.vexnum; j++) {
            if (g.arc[i][j] == INT_MAX)
                cout << "∞" << " ";
            else
            cout << g.arc[i][j] << " ";
        }
        cout << endl;
    }
}

//作为记录边的信息,这些边都是达到end的所有边中,权重最小的那个
struct Assis_array {
    int start; //边的终点
    int end;  //边的起点
    int weight;  //边的权重
};
//进行prim算法实现,使用的邻接矩阵的方法实现。
void Prim(Graph g,int begin) {

    //close_edge这个数组记录到达某个顶点的各个边中的权重最大的那个边
    Assis_array *close_edge=new Assis_array[g.vexnum];

    int j;

    //进行close_edge的初始化,更加开始起点进行初始化
    for (j = 0; j < g.vexnum; j++) {
        if (j != begin - 1) {
            close_edge[j].start = begin-1;
            close_edge[j].end = j;
            close_edge[j].weight = g.arc[begin - 1][j];
        }
    }
    //把起点的close_edge中的值设置为-1,代表已经加入到集合U了
    close_edge[begin - 1].weight = -1;
    //访问剩下的顶点,并加入依次加入到集合U
    for (j = 1; j < g.vexnum; j++) {

        int min = INT_MAX;
        int k;
        int index;
        //寻找数组close_edge中权重最小的那个边
        for (k = 0; k < g.vexnum; k++) {
            if (close_edge[k].weight != -1) {  
                if (close_edge[k].weight < min) {
                    min = close_edge[k].weight;
                    index = k;
                }
            }
        }
        //将权重最小的那条边的终点也加入到集合U
        close_edge[index].weight = -1;
        //输出对应的边的信息
        cout << g.information[close_edge[index].start] 
            << "-----" 
            << g.information[close_edge[index].end]
            << "="
            <<g.arc[close_edge[index].start][close_edge[index].end]
            <<endl;

        //更新我们的close_edge数组。
        for (k = 0; k < g.vexnum; k++) {
            if (g.arc[close_edge[index].end][k] <close_edge[k].weight) {
                close_edge[k].weight = g.arc[close_edge[index].end][k];
                close_edge[k].start = close_edge[index].end;
                close_edge[k].end = k;
            }
        }
    }
}



int main()
{
    Graph g;
    createGraph(g);//基本都是无向网图,所以我们只实现了无向网图
    print(g);
    Prim(g, 1);
    system("pause");
    return 0;
}


   

 

Bellman-Ford

 

单源最短路

Dijkstra

11.迪杰斯特拉算法

#include<bits/stdc++.h>
using namespace std;


int qwq[1005][1005];
int n,m,a,b,c;
int dis[1005];
int book[1005];
int maxn=65355;

int main()
{
    while(scanf("%d%d",&n,&m),n,m){


        memset(qwq,0,sizeof(qwq));
        memset(book,0,sizeof(book));
        memset(dis,0,sizeof(dis));
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(i==j) qwq[i][j]=0;
            else qwq[i][j]=maxn;
        }


           for(int i=1;i<=m;i++){

            scanf("%d%d%d",&a,&b,&c);
            qwq[a][b]=qwq[b][a]=c;
        }


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

            dis[i]=qwq[1][i];
        }

        book[1]=1;
		int min,u;





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

        {
             min=maxn;
             for(int j=1;j<=n;j++){


                if(book[j]==0 && min>dis[j])
                {
                    min=dis[j];
                    u=j;
                }

             }
                book[u]=1;

               for(int j=1;j<=n;j++)
               {

                    if(book[j]==0 && dis[j]>dis[u]+qwq[u][j])
                    dis[j]=dis[u]+qwq[u][j];
               }
        }


        cout<<dis[n]<<endl;
    }

}

 

SPFA

12.最短路径快速算法(Shortest Path Faster Algorithm)

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 110;
const int MAXM = 10100;
const int INF = 0x3f3f3f3f;

struct Edge
{
    int from, to, cap, next;
};

Edge edge[MAXM];
int head[MAXN];
int path[MAXN];
int inqueue[MAXN];
int dist[MAXN];
int viscnt[MAXN];
int cnt;

void addedge( int from, int to, int cap )
{
    edge[cnt].from = from;
    edge[cnt].to = to;
    edge[cnt].cap = cap;
    edge[cnt].next = head[from];
    head[from] = cnt++;
}

int relax(int u,int v,int c)
{
    if (dist[u] + c < dist[v])
    {
        dist[v] = dist[u] + c;
        return 1;
    }
    return 0;
}

bool SPFA( int src, int n )
{
    deque<int> dq;
    memset( viscnt, 0, sizeof viscnt );
    memset( inqueue, 0, sizeof inqueue );
    memset( dist, INF, sizeof dist );
    memset( path, -1, sizeof path );
    inqueue[src] = 1;
    viscnt[src]++;
    dist[src] = 0;

    dq.push_back( src );
    while (!dq.empty())
    {
        int u = dq.front();
        dq.pop_front();
        inqueue[u] = 0;

        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(dist[u] < INF&&relax( u, v, edge[i].cap ))
            {
                path[v] = u;
                if(!inqueue[v])
                {
                    inqueue[v] = 1;
                    viscnt[v]++;
                    if(viscnt[v] == n)  return false;
                    if(!dq.empty() && dist[v] <= dist[dq.front()])
                        dq.push_front( v );
                    else
                        dq.push_back( v );
                }
            }
        }
    }
    return true;
}

int main()
{
    int n,m;
    while(cin >> n >> m &&n&&m)
    {
        memset( head, -1, sizeof head );
        cnt = 0;
        for(int i = 1; i <= m; i++)
        {
            int a, b, c;
            cin >> a >> b >> c;
            addedge( a, b, c );//在a->b添加一条负载为c的边
            addedge( b, a, c );
        }
        SPFA( 1, n );
        cout << dist[n] << endl;
    }
    return 0;
}

 

Floyd-Warshall

13.弗洛伊德算法

/*
    |Floyd算法|
    |任意点对最短路算法|
    |求图中任意两点的最短距离的算法|
*/

for (int k = 0; k < n; k++) {  
    for (int i = 0; i < n; i++) {  
        for (int j = 0; j < n; j++) {  
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);  
        }  
    }
}

 

二分图

 

14.染色法

/*
    |交叉染色法判断二分图|
    |16/11/05ztx|
*/

int bipartite(int s) {  
    int u, v;  
    queue<int>Q;  
    color[s] = 1;  
    Q.push(s);  
    while (!Q.empty()) {  
        u = Q.front();  
        Q.pop();  
        for (int i = 0; i < G[u].size(); i++) {  
            v = G[u][i];  
            if (color[v] == 0) {  
                color[v] = -color[u];  
                Q.push(v);  
            }  
            else if (color[v] == color[u])  
                return 0;  
        }  
    }  
    return 1;  
}  

 

15..匈牙利算法

 

/*
    |求解最大匹配问题|
    |递归实现|
    |16/11/05ztx|
*/

vector<int>G[maxn];  
bool inpath[maxn];  //  标记  
int match[maxn];    //  记录匹配对象  
void init()  
{  
    memset(match, -1, sizeof(match));  
    for (int i = 0; i < maxn; ++i) {  
        G[i].clear();  
    }  
}  
bool findpath(int k) {  
    for (int i = 0; i < G[k].size(); ++i) {  
        int v = G[k][i];  
        if (!inpath[v]) {  
            inpath[v] = true;  
            if (match[v] == -1 || findpath(match[v])) { // 递归  
                match[v] = k; // 即匹配对象是“k妹子”的  
                return true;  
            }  
        }  
    }  
    return false;  
}  

void hungary() {  
    int cnt = 0;  
    for (int i = 1; i <= m; i++) {  // m为需要匹配的“妹子”数  
        memset(inpath, false, sizeof(inpath)); // 每次都要初始化  
        if (findpath(i)) cnt++;  
    }  
    cout << cnt << endl;  
}  
/*
    |求解最大匹配问题|
    |dfs实现|
    |16/11/05ztx|
*/

int v1, v2;  
bool Map[501][501];  
bool visit[501];  
int link[501];  
int result;  

bool dfs(int x)  {  
    for (int y = 1; y <= v2; ++y)  {  
        if (Map[x][y] && !visit[y])  {  
            visit[y] = true;  
            if (link[y] == 0 || dfs(link[y]))  {  
                link[y] = x;  
                return true;  
            } } }  
    return false;  
}  


void Search()  {  
    for (int x = 1; x <= v1; x++)  {  
        memset(visit,false,sizeof(visit));  
        if (dfs(x))  
            result++;  
    }
}

 

 

 

动态规划

背包

16.17.18背包问题

/*
    |01背包|
    |完全背包|
    |多重背包|
    |16/11/05ztx|
*/

//  01背包:  

void bag01(int cost,int weight)  {  
    for(i = v; i >= cost; --i)  
    dp[i] = max(dp[i], dp[i-cost]+weight);  
}  

//  完全背包:  

void complete(int cost, int weight)  {  
    for(i = cost ; i <= v; ++i)  
    dp[i] = max(dp[i], dp[i - cost] + weight);  
}  

//  多重背包:  

void multiply(int cost, int weight, int amount)  {  
    if(cost * amount >= v)  
        complete(cost, weight);  
    else{  
        k = 1;  
        while (k < amount){  
            bag01(k * cost, k * weight);  
            amount -= k;  
            k += k;  
        }  
        bag01(cost * amount, weight * amount);  
    }  
}  


// other

int dp[1000000];
int c[55], m[110];
int sum;

void CompletePack(int c) {
    for (int v = c; v <= sum / 2; ++v){
        dp[v] = max(dp[v], dp[v - c] + c);
    }
}

void ZeroOnePack(int c) {
    for (int v = sum / 2; v >= c; --v) {
        dp[v] = max(dp[v], dp[v - c] + c);
    }
}

void multiplePack(int c, int m) {
    if (m * c > sum / 2)
        CompletePack(c);
    else{
        int k = 1;
        while (k < m){
            ZeroOnePack(k * c);
            m -= k;
            k <<= 1;
        }
        if (m != 0){
            ZeroOnePack(m * c);
        }
    }
}

 

LIS

 

19.最长上升子序列

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
using namespace std;

const int N = 131072;

int n = 7, a[N] = {0,0,1,1,0,0,2};

template<class Cmp>
int LIS (Cmp cmp)
{
    static int m, end[N];
    m = 0;
    for (int i=0;i<n;i++)
    {
        int pos = lower_bound(end, end+m, a[i], cmp)-end;
        end[pos] = a[i], m += pos==m;
    }
    return m;
}
bool greater1(int value)
{
    return value >=1;
}

int main ()
{
    cin>>n;
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    cout << LIS(less<int>()) << endl;         //严格上升
    cout << LIS(less_equal<int>()) << endl;   //非严格上升
    cout << LIS(greater<int>()) << endl;      //严格下降
    cout << LIS(greater_equal<int>()) << endl;//非严格下降
    cout << count_if(a,a+7,greater1) << endl; //计数
    //第二个参数为末尾元素的下一个位置
    return 0;
}
//OUT:
//3 5 2 4 3

 

LCS

 

20.最长公共子序列

#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005];
char s1[1005],s2[1005];
int main()
{
    int len1,len2,i,j;
    cin>>s1>>s2;
    len1=strlen(s1);
    len2=strlen(s2);
    memset(dp,0,sizeof(dp));
    for(i=1;i<=len1;i++)
        for(j=1;j<=len2;j++)
        {
            if(s1[i-1]==s2[j-1])
                dp[i][j]=dp[i-1][j-1]+1;
            else if(dp[i-1][j]>=dp[i][j-1])
                dp[i][j]=dp[i-1][j];
            else
                dp[i][j]=dp[i][j-1];
        }
    cout<< dp[len1][len2];
}

 

计算几何

 

21.向量基本用法

/*
    |16/11/06ztx|
*/

struct node {  
    double x; // 横坐标  
    double y; // 纵坐标  
};  

typedef node Vector;

Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }  
Vector operator - (Point A, Point B) { return Vector(A.x - B.y, A.y - B.y); }  
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }  
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y*p); }  

double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } // 向量点乘  
double Length(Vector A) { return sqrt(Dot(A, A)); }  // 向量模长  
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); }  // 向量之间夹角  

double Cross(Vector A, Vector B) { // 叉积计算 公式  
    return A.x*B.y - A.y*B.x;  
}  

Vector Rotate(Vector A, double rad) // 向量旋转 公式  {  
    return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));  
}  

Point getLineIntersection(Point P, Vector v, Point Q, Vector w) { // 两直线交点t1 t2计算公式   
    Vector u = P - Q;   
    double t = Cross(w, u) / Cross(v, w);  // 求得是横坐标  
    return P + v*t;  // 返回一个点  
}  

 

22.求多边形面积

 

/*
    |16/11/06ztx|
*/

node G[maxn];  
int n;  

double Cross(node a, node b) { // 叉积计算  
    return a.x*b.y - a.y*b.x;  
}  


int main()  
{  
    while (scanf("%d", &n) != EOF && n) {  
        for (int i = 0; i < n; i++)   
            scanf("%lf %lf", &G[i].x, &G[i].y);  
        double sum = 0;  
        G[n].x = G[0].x;  
        G[n].y = G[0].y;  
        for (int i = 0; i < n; i++) {   
                sum += Cross(G[i], G[i + 1]);  
        }  
        // 或者  
            //for (int i = 0; i < n; i++) {  
                //sum += fun(G[i], G[(i + 1)% n]);  
            //}  
        sum = sum / 2.0;  
        printf("%.1f\n", sum);  
    }  
    system("pause");  
    return 0;  
}

 

23..判断线段相交

 

/*
    |16/11/06ztx|
*/

node P[35][105];     

double Cross_Prouct(node A,node B,node C) {     //  计算BA叉乘CA     
    return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);      
}      
bool Intersect(node A,node B,node C,node D)  {  //  通过叉乘判断线段是否相交;           
    if(min(A.x,B.x)<=max(C.x,D.x)&&         //  快速排斥实验;      
       min(C.x,D.x)<=max(A.x,B.x)&&      
       min(A.y,B.y)<=max(C.y,D.y)&&      
       min(C.y,D.y)<=max(A.y,B.y)&&      
       Cross_Prouct(A,B,C)*Cross_Prouct(A,B,D)<0&&      //  跨立实验;      
       Cross_Prouct(C,D,A)*Cross_Prouct(C,D,B)<0)       //  叉乘异号表示在两侧;      
       return true;      
    else return false;      
}    

24.求三角形外心
 

/*
    |16/11/06ztx|
*/

Point circumcenter(const Point &a, const Point &b, const Point &c) { //返回三角形的外心        
    Point ret;  
    double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1) / 2;  
    double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2) / 2;  
    double d = a1*b2 - a2*b1;  
    ret.x = a.x + (c1*b2 - c2*b1) / d;  
    ret.y = a.y + (a1*c2 - a2*c1) / d;  
    return ret;  
}  

 

24.极角排序

 

/*
    |16/11/06ztx|
*/

double cross(point p1, point p2, point q1, point q2) {  // 叉积计算   
    return (q2.y - q1.y)*(p2.x - p1.x) - (q2.x - q1.x)*(p2.y - p1.y);  
}  
bool cmp(point a, point b)  {  
    point o;  
    o.x = o.y = 0;  
    return cross(o, b, o, a) < 0; // 叉积判断  
}  
sort(convex + 1, convex + cnt, cmp); // 按角排序, 从小到大 

 

字符串

 

kmp

25.克努特-莫里斯-普拉特操作

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100

void cal_next( char * str, int * next, int len )
{
    int i, j;

    next[0] = -1;
    for( i = 1; i < len; i++ )
    {
        j = next[ i - 1 ];
        while( str[ j + 1 ] != str[ i ] && ( j >= 0 ) )
        {
            j = next[ j ];
        }
        if( str[ i ] == str[ j + 1 ] )
        {
            next[ i ] = j + 1;
        }
        else
        {
            next[ i ] = -1;
        }
    }
}

int KMP( char * str, int slen, char * ptr, int plen, int * next )
{
    int s_i = 0, p_i = 0;

    while( s_i < slen && p_i < plen )
    {
        if( str[ s_i ] == ptr[ p_i ] )
        {
            s_i++;
            p_i++;
        }
        else
        {
            if( p_i == 0 )
            {
                s_i++;
            }
            else
            {
                p_i = next[ p_i - 1 ] + 1;
            }
        }
    }
    return ( p_i == plen ) ? ( s_i - plen ) : -1;
}

int main()
{
    char str[ N ] = {0};
    char ptr[ N ] = {0};
    int slen, plen;
    int next[ N ];

    while( scanf( "%s%s", str, ptr ) )
    {
        slen = strlen( str );
        plen = strlen( ptr );
        cal_next( ptr, next, plen );
        printf( "%d\n", KMP( str, slen, ptr, plen, next ) );
    }
    return 0;
}

 

26.kmp扩展

 

/*
    |16/11/06ztx|
*/

#include<iostream>    
#include<cstring>    

using namespace std;

const int MM=100005;    

int next[MM],extand[MM];    
char S[MM],T[MM];    

void GetNext(const char *T) {    
    int len = strlen(T),a = 0;    
    next[0] = len;    
    while(a < len - 1 && T[a] == T[a + 1]) a++;    
    next[1] = a;    
    a = 1;    
    for(int k = 2; k < len; k ++) {    
        int p = a + next[a] - 1,L = next[k - a];    
        if( (k - 1) + L >= p) {    
            int j = (p - k + 1) > 0 ? (p - k + 1) : 0;    
            while(k + j < len && T[k + j] == T[j]) j++;    
            next[k] = j;    
            a = k;    
        }else next[k] = L;    
    }    
}    
void GetExtand(const char *S,const char *T) {    
    GetNext(T);    
    int slen = strlen(S),tlen = strlen(T),a = 0;    
    int MinLen = slen < tlen ? slen : tlen;    
    while(a < MinLen && S[a] == T[a]) a++;    
    extand[0] = a;     
    a = 0;    
    for(int k = 1; k < slen; k ++) {    
        int p = a + extand[a] - 1, L = next[k - a];    
        if( (k - 1) + L >= p) {    
            int j = (p - k + 1) > 0 ? (p - k + 1) : 0;    
            while(k + j < slen && j < tlen && S[k + j] == T[j]) j ++;    
            extand[k] = j;    
            a = k;    
        } else    
            extand[k] = L;    
    }    
}    
void show(const int *s,int len){    
    for(int i = 0; i < len; i ++)    
            cout << s[i] << ' ';    
    cout << endl;    
}    

int main() {    
    while(cin >> S >> T) {    
        GetExtand(S,T);    
        show(next,strlen(T));    
        show(extand,strlen(S));    
    }    
    return 0;    
}   

 

字典树

 

27.字典树

/*
    |16/11/06ztx|
*/

struct Trie{  
    int cnt;  
    Trie *next[maxn];  
    Trie(){  
        cnt = 0;  
        memset(next,0,sizeof(next));  
    }  
};  

Trie *root;  

void Insert(char *word)  {  
    Trie *tem = root;  
    while(*word != '\0')  {  
        int x = *word - 'a';  
        if(tem->next[x] == NULL)  
            tem->next[x] = new Trie;  
        tem = tem->next[x];  
        tem->cnt++;  
        word++;  
    }  
}  

int Search(char *word)  {  
    Trie *tem = root;  
    for(int i=0;word[i]!='\0';i++)  {  
        int x = word[i]-'a';  
        if(tem->next[x] == NULL)  
            return 0;  
        tem = tem->next[x];  
    }  
    return tem->cnt;  
}  

void Delete(char *word,int t) {  
    Trie *tem = root;  
    for(int i=0;word[i]!='\0';i++)  {  
        int x = word[i]-'a';  
        tem = tem->next[x];  
        (tem->cnt)-=t;  
    }  
    for(int i=0;i<maxn;i++)  
        tem->next[i] = NULL;  
}  

int main() {  
    int n;  
    char str1[50];  
    char str2[50];  
    while(scanf("%d",&n)!=EOF)  {  
        root = new Trie;  
        while(n--)  {  
            scanf("%s %s",str1,str2);  
            if(str1[0]=='i') {
                Insert(str2); 
            }else if(str1[0] == 's')  {  
                if(Search(str2))  
                    printf("Yes\n");  
                else  
                    printf("No\n");  
            }else  {  
                int t = Search(str2);  
                if(t)  
                    Delete(str2,t);  
            } } }  
    return 0;  
}  

 

28.AC自动机

 

/*
    |16/11/06ztx|
*/

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<string>  

using namespace std;  

#define N 1000010  

char str[N], keyword[N];  
int head, tail;  

struct node {  
    node *fail;  
    node *next[26];  
    int count;  
    node() { //init  
        fail = NULL;// 默认为空  
        count = 0;  
        for(int i = 0; i < 26; ++i)  
            next[i] = NULL;  
    }  
}*q[N];  

node *root;  

void insert(char *str)  { // 建立Trie  
    int temp, len;  
    node *p = root;  
    len = strlen(str);  
    for(int i = 0; i < len; ++i)  {  
        temp = str[i] - 'a';  
        if(p->next[temp] == NULL)  
            p->next[temp] = new node();  
        p = p->next[temp];  
    }  
    p->count++;  
}  

void build_ac() { // 初始化fail指针,BFS 数组模拟队列:   
    q[tail++] = root;  
    while(head != tail)  {  
        node *p = q[head++]; // 弹出队头  
        node *temp = NULL;  
        for(int i = 0; i < 26; ++i)  {  
            if(p->next[i] != NULL)  {  
                if(p == root) { // 第一个元素fail必指向根  
                    p->next[i]->fail = root;
                }else {  
                    temp = p->fail; // 失败指针  
                    while(temp != NULL) { // 2种情况结束:匹配为空or找到匹配 
                        if(temp->next[i] != NULL) { // 找到匹配  
                            p->next[i]->fail = temp->next[i];  
                            break;  
                        }  
                        temp = temp->fail;  
                    }  
                    if(temp == NULL) // 为空则从头匹配  
                        p->next[i]->fail = root;  
                }  
                q[tail++] = p->next[i]; // 入队  
            } } }  
}  

int query() // 扫描  
{  
    int index, len, result;  
    node *p = root; // Tire入口  
    result = 0;  
    len = strlen(str);  
    for(int i = 0; i < len; ++i)  
    {  
        index = str[i] - 'a';  
        while(p->next[index] == NULL && p != root) // 跳转失败指针  
            p = p->fail;  
        p = p->next[index];  
        if(p == NULL)  
            p = root;  
        node *temp = p; // p不动,temp计算后缀串  
        while(temp != root && temp->count != -1)   {  
            result += temp->count;  
            temp->count = -1;  
            temp = temp->fail;  
        }  
    }  
    return result;  
}  

int main() {  
    int num;  
    head= tail = 0;  
    root = new node();  
    scanf("%d", &num);  
    getchar();  
    for(int i = 0; i < num; ++i) {  
       scanf("%s",keyword);  
        insert(keyword);  
    }  
    build_ac();  
    scanf("%s", str);  
    if(query())  
        printf("YES\n");  
    else  
        printf("NO\n");  
    return 0;  
}  

/*
    假设有N个模式串,平均长度为L;文章长度为M。 建立Trie树:O(N*L) 建立fail指针:O(N*L) 模式匹配:O(M*L) 所以,总时间复杂度为:O( (N+M)*L )。
*/

 

线段树

 

29.线段树 

1)点更新

/*
    |16/12/07ztx|
*/

struct node
{
    int left, right;
    int max, sum;
};

node tree[maxn << 2];
int a[maxn];
int n;
int k = 1;
int p, q;
string str;

void build(int m, int l, int r)//m 是 树的标号
{
    tree[m].left = l;
    tree[m].right = r;
    if (l == r){
        tree[m].max = a[l];
        tree[m].sum = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(m << 1, l, mid);
    build(m << 1 | 1, mid + 1, r);
    tree[m].max = max(tree[m << 1].max, tree[m << 1 | 1].max);
    tree[m].sum = tree[m << 1].sum + tree[m << 1 | 1].sum;
}

void update(int m, int a, int val)//a 是 节点位置, val 是 更新的值(加减的值)
{
    if (tree[m].left == a && tree[m].right == a){
        tree[m].max += val;
        tree[m].sum += val;
        return;
    }
    int mid = (tree[m].left + tree[m].right) >> 1;
    if (a <= mid){
        update(m << 1, a, val);
    }
    else{
        update(m << 1 | 1, a, val);
    }
    tree[m].max = max(tree[m << 1].max, tree[m << 1 | 1].max);
    tree[m].sum = tree[m << 1].sum + tree[m << 1 | 1].sum;
}

int querySum(int m, int l, int r)
{
    if (l == tree[m].left && r == tree[m].right){
        return tree[m].sum;
    }
    int mid = (tree[m].left + tree[m].right) >> 1;
    if (r <= mid){
        return querySum(m << 1, l, r);
    }
    else if (l > mid){
        return querySum(m << 1 | 1, l, r);
    }
    return querySum(m << 1, l, mid) + querySum(m << 1 | 1, mid + 1, r);
}

int queryMax(int m, int l, int r)
{
    if (l == tree[m].left && r == tree[m].right){
        return tree[m].max;
    }
    int mid = (tree[m].left + tree[m].right) >> 1;
    if (r <= mid){
        return queryMax(m << 1, l, r);
    }
    else if (l > mid){
        return queryMax(m << 1 | 1, l, r);
    }
    return max(queryMax(m << 1, l, mid), queryMax(m << 1 | 1, mid + 1, r));
} 

build(1,1,n);  
update(1,a,b);  
query(1,a,b);  

 

2)区间更新

 

/*
    |16/11/06ztx|
*/

typedef long long ll;  
const int maxn = 100010;  

int t,n,q;  
ll anssum;  

struct node{  
    ll l,r;  
    ll addv,sum;  
}tree[maxn<<2];  

void maintain(int id) {  
    if(tree[id].l >= tree[id].r)  
        return ;  
    tree[id].sum = tree[id<<1].sum + tree[id<<1|1].sum;  
}  

void pushdown(int id) {  
    if(tree[id].l >= tree[id].r)  
        return ;  
    if(tree[id].addv){  
        int tmp = tree[id].addv;  
        tree[id<<1].addv += tmp;  
        tree[id<<1|1].addv += tmp;  
        tree[id<<1].sum += (tree[id<<1].r - tree[id<<1].l + 1)*tmp;  
        tree[id<<1|1].sum += (tree[id<<1|1].r - tree[id<<1|1].l + 1)*tmp;  
        tree[id].addv = 0;  
    }  
}  

void build(int id,ll l,ll r) {  
    tree[id].l = l;  
    tree[id].r = r;  
    tree[id].addv = 0;  
    tree[id].sum = 0;  
    if(l==r)  {  
        tree[id].sum = 0;  
        return ;  
    }  
    ll mid = (l+r)>>1;  
    build(id<<1,l,mid);  
    build(id<<1|1,mid+1,r);  
    maintain(id);  
}  

void updateAdd(int id,ll l,ll r,ll val) {  
    if(tree[id].l >= l && tree[id].r <= r)  
    {  
        tree[id].addv += val;  
        tree[id].sum += (tree[id].r - tree[id].l+1)*val;  
        return ;  
    }  
    pushdown(id);  
    ll mid = (tree[id].l+tree[id].r)>>1;  
    if(l <= mid)  
        updateAdd(id<<1,l,r,val);  
    if(mid < r)  
        updateAdd(id<<1|1,l,r,val);  
    maintain(id);  
}  

void query(int id,ll l,ll r) {  
    if(tree[id].l >= l && tree[id].r <= r){  
        anssum += tree[id].sum;  
        return ;  
    }  
    pushdown(id);  
    ll mid = (tree[id].l + tree[id].r)>>1;  
    if(l <= mid)  
        query(id<<1,l,r);  
    if(mid < r)  
        query(id<<1|1,l,r);  
    maintain(id);  
}  

int main() {  
    scanf("%d",&t);  
    int kase = 0 ;  
    while(t--){  
        scanf("%d %d",&n,&q);  
        build(1,1,n);  
        int id;  
        ll x,y;  
        ll val;  
        printf("Case %d:\n",++kase);  
        while(q--){  
            scanf("%d",&id);  
            if(id==0){  
                scanf("%lld %lld %lld",&x,&y,&val);  
                updateAdd(1,x+1,y+1,val);  
            }  
            else{  
                scanf("%lld %lld",&x,&y);  
                anssum = 0;  
                query(1,x+1,y+1);  
                printf("%lld\n",anssum);  
            } } }  
    return 0;  
}  

 

30.树状数组

 

/*
    |16/11/06ztx|
*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>

using namespace std;

typedef long long ll;

const int maxn = 50005;

int a[maxn];
int n;

int lowbit(const int t) {
    return t & (-t);
}

void insert(int t, int d) {
    while (t <= n){
        a[t] += d;
        t = t + lowbit(t);
    }
}

ll getSum(int t) {
    ll sum = 0;
    while (t > 0){
        sum += a[t];
        t = t - lowbit(t);
    }
    return sum;
}

int main() {
    int t, k, d;
    scanf("%d", &t);
    k= 1;
    while (t--){
        memset(a, 0, sizeof(a));
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &d);
            insert(i, d);
        }
        string str;
        printf("Case %d:\n", k++);
        while (cin >> str) {
            if (str == "End")   break;
            int x, y;
            scanf("%d %d", &x, &y);
            if (str == "Query")
                printf("%lld\n", getSum(y) - getSum(x - 1));
            else if (str == "Add")
                insert(x, y);
            else if (str == "Sub")
                insert(x, -y);
        }
    }
    return 0;
}

 

其他

 

31.中国剩余定理(孙子定理)

/*
    |16/11/06ztx|
*/

int CRT(int a[],int m[],int n)  {    
    int M = 1;    
    int ans = 0;    
    for(int i=1; i<=n; i++)    
        M *= m[i];    
    for(int i=1; i<=n; i++)  {    
        int x, y;    
        int Mi = M / m[i];    
        extend_Euclid(Mi, m[i], x, y);    
        ans = (ans + Mi * x * a[i]) % M;    
    }    
    if(ans < 0) ans += M;    
    return ans;    
}  

void extend_Euclid(int a, int b, int &x, int &y)  {  
    if(b == 0) {  
        x = 1;  
        y = 0;  
        return;  
    }  
    extend_Euclid(b, a % b, x, y);  
    int tmp = x;  
    x = y;  
    y = tmp - (a / b) * y;  
}  

32.判断字符串是否包含某个子串

#include<bits/stdc++.h>  
using namespace std;  
  
int main()  
{     
    //定义两个相同部分为hello的字符串  
    string str1="asdasdadhelloz,zxc";  
    string str2="hello";  
     
   //应该是一个类似迭代器的东西…还没有研究透  
    string::size_type id = str1.find(str2);  
      
    if(id != string::npos )  
    {  
        cout<<"字符串中含有"<<str2<<endl;  
    }  
      
    else   
    {  
        cout<<"字符串中不含有"<<str2<<endl;  
    }  
}  

33.模拟二(n)进制相加

#include<bits/stdc++.h>
using namespace std;

char a[105],b[105];
int ans[105];


int main()
{
    cin>>a>>b;
    int len = strlen(a);
    for(int i=len-1;i>0;i--)
    {
        ans[i] +=a[i]-48 + b[i] -48;
        //开始模拟进位
        ans[i-1] += ans[i] /2;
        ans[i] = ans[i]%2;
    }
    ans[0] += a[0] -48+b[0] -48;

    if(ans[0] > 1) cout<<ans[0]/2<<ans[0] %2;

    else cout<<ans[0];

    for(int i=1;i<len;i++)
    {
        cout<<ans[i];
    }
}

34.

Wannafly模拟赛 矩阵 [矩阵hash+二分]

 

题目描述

给出一个n * m的矩阵。让你从中发现一个最大的正方形。使得这样子的正方形在矩阵中出现了至少两次。输出最大正方形的边长。

输入描述:

第一行两个整数n, m代表矩阵的长和宽;
接下来n行,每行m个字符(小写字母),表示矩阵;

输出描述:

输出一个整数表示满足条件的最大正方形的边长。

示例1

输入

5 10
ljkfghdfas
isdfjksiye
pgljkijlgp
eyisdafdsi
lnpglkfkjl

输出

3

备注:

对于30%的数据,n,m≤100;
对于100%的数据,n,m≤500;

 

 

 

思路:

 

二分答案,然后Hash一下就行。

 

Ac代码:

 

#include<stdio.h>  
#include<string.h>  
#include<map>  
#include<algorithm>  
#include<iostream>  
using namespace std;  
char a[505][505];  
unsigned long long int h[505][505];  
unsigned long long int X[505*505];  
int n,m;  
const int maxn=350000;  
const int hashh=1000007;  
   
struct hashmap  
{  
    unsigned long long int a[maxn];  
    int head[hashh];  
    int next[maxn];  
    int size;  
    void init()  
    {  
        memset(head,-1,sizeof(head));  
        size=0;  
    }  
    bool find(unsigned long long int val)  
    {  
        int tmp=(val%hashh+hashh)%hashh;  
        for(int i=head[tmp];i!=-1;i=next[i])  
        {  
            if(val==a[i])return true;  
        }  
        return false;  
    }  
    void add(unsigned long long int val)  
    {  
        int tmp=(val%hashh+hashh)%hashh;  
        if(find(val))return ;  
        a[size]=val;  
        next[size]=head[tmp];//令next指向-1、  
        head[tmp]=size++;  
    }  
}H;  
int Slove(int mid)  
{  
    H.init();  
    map<unsigned long long int,int>s;  
    for(int i=1;i<=n;i++)  
    {  
        for(int j=1;j<=m;j++)  
        {  
            int x=i,y=j;  
            int xx=i+mid-1,yy=j+mid-1;  
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m)  
            {  
                unsigned long long int val=h[xx][yy]+h[x-1][y-1]-h[xx][y-1]-h[x-1][yy];  
                val*=X[(n-i)*m+m-j];  
                if(H.find(val)==true)return 1;  
                else H.add(val);  
            }  
        }  
    }  
    return 0;  
}  
int main()  
{  
    while(~scanf("%d%d",&n,&m))  
    {  
        memset(h,0,sizeof(h));  
        for(int i=1;i<=n;i++)scanf("%s",a[i]+1);  
        X[0]=1;  
        for(int i=1;i<=n;i++)  
        {  
            for(int j=1;j<=m;j++)  
            {  
                h[i][j]=h[i][j-1]+X[(i-1)*m+j-1]*(a[i][j]-'a');  
                X[(i-1)*m+j]=X[(i-1)*m+j-1]*19260817;  
            }  
        }  
        for(int j=1;j<=m;j++)  
        {  
            for(int i=1;i<=n;i++)  
            {  
                h[i][j]=h[i][j]+h[i-1][j];  
            }  
        }  
        int ans=0;  
        int l=0;  
        int r=min(n,m);  
        while(r-l>=0)  
        {  
            int mid=(l+r)/2;  
            if(Slove(mid)==1)  
            {  
                ans=mid;  
                l=mid+1;  
            }  
            else r=mid-1;  
        }  
        printf("%d\n",ans);  
    }  
}  

 

 

 

 

ACM 算法模板集 Contents 一. 常用函数与STL 二. 重要公式与定理 1. Fibonacci Number 2. Lucas Number 3. Catalan Number 4. Stirling Number(Second Kind) 5. Bell Number 6. Stirling's Approximation 7. Sum of Reciprocal Approximation 8. Young Tableau 9. 整数划分 10. 错排公式 11. 三角形内切圆半径公式 12. 三角形外接圆半径公式 13. 圆內接四边形面积公式 14. 基础数论公式 三. 大数模板,字符读入 四. 数论算法 1. Greatest Common Divisor最大公约数 2. Prime素数判断 3. Sieve Prime素数筛法 4. Module Inverse模逆元 5. Extended Euclid扩展欧几里德算法 6. Modular Linear Equation模线性方程(同余方程) 7. Chinese Remainder Theorem中国余数定理(互素于非互素) 8. Euler Function欧拉函数 9. Farey总数 9. Farey序列构造 10. Miller_Rabbin素数测试,Pollard_rho因式分解 五. 图论算法 1. 最小生成树(Kruscal算法) 2. 最小生成树(Prim算法) 3. 单源最短路径(Bellman-ford算法) 4. 单源最短路径(Dijkstra算法) 5. 全源最短路径(Folyd算法) 6. 拓扑排序 7. 网络预流和最大流 8. 网络最小费用最大流 9. 网络最大流(高度标号预流推进) 10. 最大团 11. 二分图最大匹配(匈牙利算法) 12. 带权二分图最优匹配(KM算法) 13. 强连通分量(Kosaraju算法) 14. 强连通分量(Gabow算法) 15. 无向图割边割点和双连通分量 16. 最小树形图O(N^3) 17. 最小树形图O(VE) 六. 几何算法 1. 几何模板 2. 球面上两点最短距离 3. 三点求圆心坐标 4. 三角形几个重要的点 七. 专题讨论 1. 树状数组 2. 字典树 3. 后缀树 4. 线段树 5. 并查集 6. 二叉堆 7. 逆序数(归并排序) 8. 树状DP 9. 欧拉路 10. 八数码 11. 高斯消元法 12. 字符串匹配(KMP算法) 13. 全排列,全组合 14. 二维线段树 15. 稳定婚姻匹配 16. 后缀数组 17. 左偏树 18. 标准RMQ-ST 19. 度限制最小生成树 20. 最优比率生成树(0/1分数规划) 21. 最小花费置换 22. 区间K大数 23. LCA - RMQ-ST 24. LCA – Tarjan 25. 指数型母函数 26. 指数型母函数(大数据) 27. 单词前缀树(字典树+KMP) 28. FFT(大数乘法) 29. 二分图网络最大流最小割 30. 混合图欧拉回路 31. 无源汇上下界网络流 32. 二分图最小点权覆盖 33. 带约束的轨道计数(Burnside引理) 34. 三分法求函数波峰 35. 单词计数,矩阵乘法 36. 字符串和数值hash 37. 滚动队列,前向星表示法 38. 最小点基,最小权点基
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值