Home 算法板子
Post
Cancel

算法板子

第一部分 动态规划

最大连续子数字和

1
2
3
4
5
6
7
8
int maxSubArray(vector<int>& nums) {
    int pre = 0, maxAns = nums[0];
    for (const auto &x: nums) {
        pre = max(pre + x, x);
        maxAns = max(maxAns, pre);
    }
    return maxAns;
}

01背包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#define MAX 1001
using namespace std;

int dp[MAX];

int main() {
    int w[MAX], v[MAX], n, wei;

    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &w[i], &v[i]);
    }
    scanf("%d", &wei);

    // Dynamic Programming START
    for (int i = 1; i <= n; i++) {
        for (int j = wei; j >= w[i]; j--) {
            dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
        }
    }
    // END

    printf("%d\n", dp[wei]);

    return 0;
}

/*
运行时间:O(n*wei)
Example:
Input:
4
2 3
1 2
3 4
2 2
5

Output:
7
Program ended with exit code: 0

*/

完全背包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#define MAX 1001
using namespace std;

int dp[MAX];

int main() {
    int w[MAX], v[MAX], n, wei;
  
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &w[i], &v[i]);
    }
    scanf("%d", &wei);
  
    // Dynamic Programming START
    for (int i = 1; i <= n; i++) {
        for (int j = w[i]; j <= wei; j++) {
            dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
        }
    }
    // END
    printf("%d\n", dp[wei]);  
    return 0;
}

/*
运行时间:O(n*wei)
Example:
Input:
4
2 3
1 2
3 4
2 2
5

Output:
10
Program ended with exit code: 0
*/

图论

dijkstra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <queue>
using namespace std;

const int N = 500;
const int INF = 99999999;


int vis[N];
int dis[N];

int iMap[N][N];
int vertexs;
int edges;//这里有个玄学问题,如果edges 放在vis[N],之前的话程序无法运行。。
int u, v, w;

int dijkstraHeap(int beginX, int endX)
{
	int minVertex;
	priority_queue<pair<int,int>, vector<pair<int,int> >, greater<pair<int,int> > > heap;//一个最小堆

	//初始化
	for(int i=1;i<=vertexs;i++){
		dis[i] = iMap[beginX][i];//初始化所有点到开始点的最短距离
		heap.push(make_pair(dis[i], i));//初始的话先将所有的点入队
		vis[i] = 0;
	}
	vis[beginX] = 1;

	while(!heap.empty()){
		minVertex = heap.top().second;
		heap.pop();

		if(vis[minVertex]) continue;//如果这个点之前没有被访问过
		vis[minVertex] = 1;

		int u = minVertex;
		for(int v=1;v<=vertexs;v++){
			if(!vis[v] && iMap[u][v] < INF){//如果这个点未被访问,且中间有路径到达
				if(dis[v] > iMap[u][v] + dis[u]){
					dis[v] = iMap[u][v] + dis[u];
					heap.push(make_pair(dis[v], v));//将到更新后的到该点的距离入队
				}
			}
		}
	}
	return dis[endX];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#define MAX 1001
using namespace std;

int main() {
    int inf = MAX, nodeCount, lineCount, x, y, s, point, u = 0, minimum;
    int map[MAX][MAX], dis[MAX];
    bool book[MAX];
  
    for (int i = 0; i < MAX; i++) {
        book[i] = false;
        for (int j = 0; j < MAX; j++) {
            if (i == j) map[i][j] = 0;
            else map[i][j] = inf;
        }
    }
  
    scanf("%d%d", &nodeCount, &lineCount);
    for (int i = 0; i < lineCount; i++) {
        scanf("%d%d%d", &x, &y, &s);
        map[x][y] = s;
    }
    scanf("%d", &point);
  
    // Dijkstra START
    for (int i = 0; i < nodeCount; i++) {
        dis[i] = map[point][i];
    }
  
    book[point] = true;
  
    for (int i = 0; i < nodeCount; i++) {
        minimum = inf;
        for (int j = 0; j < nodeCount; j++) {
            if (!book[j] && dis[j] < minimum) {
                minimum = dis[j];
                u = j;
            }
        }
        book[u] = true;
        for (int j = 0; j < nodeCount; j++)
            if (map[u][j] < inf)
                dis[j] = min(dis[j], dis[u] + map[u][j]);
    }
    // END
  
    for (int i = 0; i < nodeCount; i++) {
        printf("%d -> %d: ", point, i);
        if (dis[i] >= inf) printf("can not reach\n");
        else printf("%d\n", dis[i]);
    }
  
    return 0;
}

/*

求单源最短路径
运行时间:O(n^2) // 用堆和邻接表优化可以降至 O(m+N)logN

Example:

Input:
3 4
0 1 1
1 2 2
2 0 3
0 2 2
1

Output:
1 -> 0: 5
1 -> 1: 0
1 -> 2: 2
Program ended with exit code: 0

*/

度序列可简单验证 Erdős–Gallai

$S=(d_1,d_2,…,d_n)$为多个非负整数组成的非递增序列 S可简单图化当且仅当这些数字的和为偶数,且 $\sum^k_{i=1}d_i\leqslant k(k-1)+ \sum^k_{i=k+1} min(d_i,k)$ $1 \leqslant k \leqslant n$对于任意都成立。 对前k个点分配度数,除了两两能连k(k-1)/2 边外,剩下的度数由后面点的度数补充。 因为di非递增,从小到大枚举k,维护di后缀与k取min的和

d是终点,counter是入度统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int d[MAXN], counter[MAXN];
int n;

bool erdos_gallai() {
    memset(counter, 0, sizeof(counter));
    for (int i = 0; i < n; i++) counter[d[i]]++;
  
    int remaining = 0, i = 0, cur;
    ll left = 0, right = 0;
    for (int k = 0; k < n; k++) {
        cur = d[i++];
        left += cur;
        counter[cur]--;

        remaining += counter[k];
        right += n - k - remaining - min(cur, k);

        if (left > (ll)k * (k + 1) + right) {
            return false;
        }
    }

    return true;
}

Floyd-Warshall 多源最小路程

1
2
3
4
5
for (int k = 0; k < nodeCount; k++)
    for (int i = 0; i < nodeCount; i++)
        for (int j = 0; j < nodeCount; j++)
            map[i][j] = min(map[i][j], map[i][k] + map[k][j]);

KM 最优图匹配

完备匹配:定义 设G=为二部图,|V1|≤|V2|,M为G中一个最大匹配,且|M|=|V1|,则称M为V1到V2的完备匹配。也就是说把一个集合中的点全部匹配到另一个集合中。 二分图带权匹配与最优匹配:什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和最大或最小,这个匹配集合比一定是完备匹配。 对二分图G和一组可行标, 满足可行标边界条件(lx[i]+ly[j]=w[i,j])的所有边构成的生成子图(需要包含所有顶点), 称为其等价子图(相等子图), 在这个等价子图上,寻找其完备匹配,如果完备匹配存在,则这个完备匹配M就是图G的最大权匹配, 最大权等于所有可行标的和; 如果完备匹配不存在,则修改可行标,用贪心的思想,将最优的边加入等价子图. Kuhn-Munkras算法流程: (1)初始化可行顶标的值 (2)用匈牙利算法寻找完备匹配 (3)若未找到完备匹配则修改可行顶标的值 (4)重复(2)(3)直到找到相等子图的完备匹配为止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/******************************************************
二分图最佳匹配 (kuhn munkras 算法 O(m*m*n)).
邻接矩阵形式 。  返回最佳匹配值,传入二分图大小m,n
邻接矩阵 mat ,表示权,match1,match2返回一个最佳匹配,为匹配顶点的match值为-1,
一定注意m<=n,否则循环无法终止,最小权匹配可将全职取相反数。
初始化:  for(i=0;i<MAXN;i++)
             for(j=0;j<MAXN;j++) mat[i][j]=-inf;
对于存在的边:mat[i][j]=val;//注意不能负值 
********************************************************/
#include<string.h>
#define MAXN 310
#define inf 1000000000 
#define _clr(x) memset(x,-1,sizeof(int)*MAXN)
int KM(int m,int n,int mat[][MAXN],int *match1,int *match2)
{
        int s[MAXN],t[MAXN],l1[MAXN],l2[MAXN];
    int p,q,i,j,k,ret=0;
    for(i=0;i<m;i++)
    {
        l1[i]=-inf;
        for(j=0;j<n;j++)
            l1[i]=mat[i][j]>l1[i]?mat[i][j]:l1[i];
        if(l1[i]==-inf)  return -1;
    } 
    for(i=0;i<n;i++)
        l2[i]=0;
    _clr(match1);
    _clr(match2);
    for(i=0;i<m;i++)
    {
        _clr(t);
        p=0;q=0;
        for(s[0]=i;p<=q&&match1[i]<0;p++)
        {
            for(k=s[p],j=0;j<n&&match1[i]<0;j++)
            {
                if(l1[k]+l2[j]==mat[k][j]&&t[j]<0)
                {
                    s[++q]=match2[j];
                    t[j]=k;
                    if(s[q]<0)
                    {
                        for(p=j;p>=0;j=p)
                        {
                            match2[j]=k=t[j];
                            p=match1[k];
                            match1[k]=j;
                        }  
                    }  
                }  
            }  
        } 
        if(match1[i]<0)
        {
            i--;
            p=inf;
            for(k=0;k<=q;k++)
            {
                for(j=0;j<n;j++)
                {
                    if(t[j]<0&&l1[s[k]]+l2[j]-mat[s[k]][j]<p)
                       p=l1[s[k]]+l2[j]-mat[s[k]][j];
                }  
            }  
            for(j=0;j<n;j++)
               l2[j]+=t[j]<0?0:p;
            for(k=0;k<=q;k++)
               l1[s[k]]-=p;  
        }     
    } 
    for(i=0;i<m;i++)
        ret+=mat[i][match1[i]];
    return ret;    
}

This post is licensed under CC BY 4.0 by the author.