// maxSumSqu为最大平方和 int n, k, x, maxSumSqu = -1, a[maxn]; // temp存放临时方案,ans存放平方和最大的方案 vector<int> temp, ans;
voidDFS(int index, int tempK, int sum, int sumSqu){ if (tempK = k && sum == x) { if (sumSqu > maxSumSqu) { maxSumSqu = sumSqu; ans = temp; } return; } if (tempK > k || index == n || sum > x) return; temp.push_back(a[index]); DFS(index + 1, tempK + 1, sum + a[index], sumSqu + a[index] * a[index]); temp.pop_back(); DFS(index + 1, tempK, sum, sumSqu); }
structNode { int x, y; int step; // 表示步长 } s, t, node;
int n, m; char maze[maxn][maxn]; bool inq[maxn][maxn] = {false}; int x[4] = {0, 0, 1, -1}; int y[4] = {1, -1, 0, 0};
// 检测位置是否有效 booltest(int x, int y){ if (x >= n || x < 0 || y >= m || y < 0) returnfalse; if (maze[x][y] == ‘*’) returnfalse; if (inq[x][y] == true) returnfalse; returntrue; }
intBFS(){ queue<Node> q; q.push(s); while (!q.empty()) { Node top = q.front(); q.pop(); if (top.x = t.x && top.y == t.y) return top.step; for (int i = 0; i < 4; i++) { int newx = top.x + x[i]; int newy = top.y + y[i]; if (test(newx, newy)) { node.x = newx; node.y = newy; node.step = top.step + 1; q.push(node); inq[newx][newy] = true; } } return-1; } }
intmain(){ scanf(“%d%d”, &n, &m); for (int i = 0; i < n; i++) { getchar(); for (int j = 0; j < m; j++) { maze[x][y] = getchar(); } maze[x][m+1] = ‘\0’; } scanf(“%d%d%d%d”, &s.x, &s.y, &t.x, &t.y); s.step = 0; printf(“%d”, BFS()); return0; }
int father[N]; //初始化并查集 voidinit(){ for (int i = 1; i <= N; i++) { father[i] = i; } } //查找根结点操作 intfindFather(int x){ int a = x; //a会被根结点替换掉,先储存 while (x != father[x]) { x = father[x]; } while (a != father[a]) { int z = a; //a会被father[a]替换掉,先储存 a = father[a]; father[z] = x; } return x; } //合并两个集合 voidunion(int a, int b){ int fa = findFather(a); int fb = findFather(b); if (fa != fb) { father[fa] = fb; } }
#include<iostream> usingnamespace std; constint N = 110; int father[N]; bool flag[N]; intfindFather(int x){ int a = x; while (x != father[x]) x = father[x]; // 缩短路径 while (a != father[a]) { int z = a; a = father[a]; father[z] = x; } return x; } voidUnion(int a, int b){ int faA = findFather(a); int faB = findFather(b); if (faA != faB) father[faA] = faB; } voidinit(int n){ for (int i = 1; i <= n; i++) { father[i] = i; flag[i] = false; } } intmain(){ int n, m, a, b, cnt = 0; scanf("%d%d", &n, &m); init(n); for (int i = 0; i < m; i++) { scanf("%d%d", &a, &b); Union(a, b); } for (int i = 1; i <= n; i++) { flag[findFather(i)] = true; } for (int i = 1; i <= n; i++) { if (flag[i] == true) cnt++; } printf("%d", cnt); }
vector<int> adj[maxn]; int n; bool inq[maxn]; voidBFS(int u){ inq[u] = true; queue<int> q; q.push(u); while (!q.empty()) { int u = q.front(); q.pop(); for (int v = 0; v < adj[u].size(); v++) { int v = adj[u][v]; if (inq[v] == false) { q.push(v); inq[v] = true; } } } } voidBFSTravel(){ for (int i = 0; i < n; i++) { if (inq[i] == false) { BFS(i); } } }
int optValue; //表示第二标尺最优值 vector<int> pre[maxn]; vector<int> path, tempPath; //最优路径和临时最优路径 voidDFS(int s){ //递归边界 if (v == st) { //到达了叶子结点st tempPath.push_back(v); int value; value = tempPath上的value值 if (value 优于 optValue) { optValue = value; path = tempPath; } tempPath.pop(); return; } //递归式 tempPath.push_back(v); for (int i = 0; i < pre[v].size(); i++) { DFS(pre[v][i]); } tempPath.pop_back(); }
访问部分(因为递归的原因,所以一般要逆向访问)
1 2 3 4 5 6 7 8 9 10 11 12
//边权部分 int value = 0; for (int i = tempPath.size() - 1; i > 0; i--) { int id = tempPath[i], nextId = tempPath[i-1]; value += v[i][i-1]; //value增加id->idNext的边权 } //点权部分 int value = 0; for (int i = tempPath.size() - 1; i > 0; i--) { int id = tempPath[i]; value += w[i]; //value增加id的点权 }
#include<iostream> #include<algorithm> usingnamespace std; constint maxv = 110; //最大顶点数 constint maxe = 11000; //最大边数 int n, m; //n为顶点数,m为边数 int father[maxv]; //并查集来判断是否为连通图 structEdge { int u, v; //表示边的两个顶点 int value; //边权值 } edge[maxe]; boolcmp(Edge a, Edge b){ return a.value < b.value; } intfindFather(int x){ int a = x; while (a != father[a]) { a = father[a]; //寻找父亲,循环结束时a储存该连通图的根结点 } while (x != father[x]) { //路径压缩 int z = x; //先储存,x会被father[x]替换掉 x = father[x]; father[z] = a; } return a; } intKruskal(){ int ans = 0, numEdge = 0; //ans表示最小生成树边权值和,numEdge表示边数 for (int i = 0; i < m; i++) { if (numEdge == n - 1) break; int fau = findFather(edge[i].u); int fav = findFather(edge[i].v); if (fau != fav) { //说明两个联通分量独立 father[fau] = fav; ans += edge[i].value; numEdge++; } } if (numEdge != n - 1) return-1; //说明整个图不联通 return ans; } intmain(){ scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { //初始化并查集 father[i] = i; } for (int i = 0; i < m; i++) { scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].value); } sort(edge, edge + m, cmp); int ans = Kruskal(); printf("%d", ans); return0; }
vector<int> g[maxn]; //邻接表 int n, m, inDegree[maxn]; //表示顶点数,边数和入度 //拓扑排序 booltopuSort(){ //当为有向无环图时返回true int num = 0; queue<int> q; for (int i = 0; i < n; i++) { //如果入度为0,则入队 if (inDegree[i] == 0) { q.push(i); } } while (!q.empty()) { int u = q.front(); q.pop(); for (int i = 0; i < g[u].size(); i++) { int v = g[u][i]; //后继结点 inDegree[v]—-; if (inDegree[v] == 0) { q.push(v); } } num++; } if (num == n) returntrue; elsereturnfalse; }
intmain(){ int n, k; scanf(“%d”, &n); for (int i = 0; i < n; i++) { scanf(“%d”, &a[i]); } dp[0] = a[0]; for (int i = 1; i < n; i++) { dp[i] = max{a[i], dp[i-1] + a[i]}; } for (int i = 1; i < n; i++) { if (dp[i] > dp[k]) k = i; } printf(“%d”, dp[k]); }
#include<iostream> usingnamespace std; int dp[1001][1001]; intmain(){ string s; can >> s; int len = s.length(), ans = 1; memset(dp, 0, sizeof(dp)); // dp数组初始化为0 for (int i = 0; i < len; i++) { dp[i][i] = 1; if (i < len - 1) { if (s[i] == s[i+1]) { dp[i][i+1] = 1; ans = 2; } } } // 状态转移方程 for (int l = 3; l <= len; l++) { for (int i = 0; l + i - 1 < len; i++) { int j = l + i - 1; if (s[i] == s[j] && dp[i+1][j-1] == 1) { dp[i][j] = 1; ans = l; } } } printf(“%d”, ans); return0; }
#include<iostream> #include<algorithm> usingnamespace std; int w[100], c[100], dp[1000]; intmain(){ int n, V; scanf(“%d%d”, &n, &V); for (int i = 1; i <= n; i++) scanf(“%d”, &w[i]); for (int i = 1; i <= V; i++) scanf(“%d”, &c[i]); memset(dp, 0, sizeof(dp)); for (int i = 1; i <= n; i++) { for (int v = V; v >= w[i]; v--) { dp[v] = max(dp[v], dp[v-w[i]] + c[i]); } } int maxn = 0; for (int v = 0; v <= V; v++) { if (dp[v] > maxn) maxn = dp[v]; } printf(“%d”, maxn); return0; }
if (n % prime[i] == 0) { fac[num].x = prime[i]; fac[num].cnt = 0; while (n % prime[i] == 0) { fac[num].cnt++; n /= prime[i]; } num++; }
大整数运算
大整数储存
1 2 3 4 5 6 7 8
structbign { int d[1000]; int len; // 储存该大整数的长度,很有用 bign () { // 初始化该结构体,默 memset(d, 0, sizeof(d)); len = 0; } };
高精度加法
1 2 3 4 5 6 7 8 9 10 11 12 13
bign add(bign a, bign b){ bign c; int carry = 0; // 表示进位值 for (int i = 0; i < a.len || i < b.len; i++) { int temp = a.d[i] + b.d[i] + carry; c.d[c.len++] = temp % 10; carry = temp / 10; } if (carry != 0) { // 如果最后进位不为0,则直接赋值给最高位 c.d[c.len++] = carry; } return c; }
高精度减法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
bign sub(bign a, bign b){ // a为减数,b为被减数 bign c; for (int i = 0; i < a.len || i < b.len; i++) { if (a.d[i] < b.d[i]) { a.d[i+1]—-; a.d[i] += 10; } c.d[c.len++] = a.d[i] - b.d[i]; } while (c.len - 1 > 1 && c.d[c.len-1] == 0) { c.len—-; // 去除最高位的0,同时至少保留一位最低位 } return c; }
高精度与低精度的乘法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
bign multi(bign a, int b){ bign c; int carry = 0; for (int i = 0; i < a.len; i++) { int temp = a.d[i] * b + carry; c.d[len++] = temp % 10; carry = temp / 10; } while (carry != 0) { c.d[c.len++] = carry % 10; carry /= 10; } return c; }
高精度与低精度的除法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
bign divide(bign a, bign b, int& r){ bign c; c.len = a.len; // 被除数的每一位和商的每一位是一一对应的,先令长度相等 for(int i = a.len - 1; i >= 0; i--) { // 从高位开始 r = r * 10 + a.d[i]; // 与上一位留下的余数组合 if (r < b) c.d[i] = 0; // 不够除,该位为0 else { // 够除 c.d[i] = r / b; r = r % b; } } while (c.len - 1 >= 1 && c.d[c.len - 1] == 0) { c.len--; } return c; }
拓展欧几里得算法
给定两个非零整数a和b,求一组整数解(x,y),使得ax + by = gcd(a,b)成立。推导可以得到一个递推公式,。其中x1,y1表示新值,x2,y2表示旧值。
1 2 3 4 5 6 7 8 9 10 11 12
intexGcd(int a, int b, int &x, int &y){ if (b == 0) { x = 1; y = 0; return a; // 此处的a即为边界的gcd } int g = exGcd(b, a % b, x, y); int temp = x; // 存放x值 x = y; // 更新x = y(old) y = temp - a / b * y; // 更新y = x(old) - a / b * y(old) return g; }
此处x和y使用引用是因为保留对x和y的更新。
组合数
求n!中有多少个质因子p。
1 2 3 4 5 6 7 8 9
// 计算n!中有多少质因子p intcal(int n, int p){ int ans = 0; while (n) { ans += n / p; // 累加n/p^k n /= p; // 相当于分母多乘一个p } return ans; }