蓝桥杯常用小技巧
- 将一个数的每一位取出
while(x)
{
int t = x % 10;
x /= 10;
}
- 将一个数字字符串转换为数字
int x = 0;
for(int i = 0; i < s.size(); i ++ )
{
x = x * 10 + s[i] - '0';
}
- 判断日期是否合法
- 宽搜BFS的一般写法
bfs能找到最短路径,dfs不能找最短路径
需要判重数组st[]、队列
queue<-初始状态
while(queue非空)
{
取出队头t
for(扩展t)
{
ver<-新节点
if(!st[ver])
{
queue<-ver // 入队尾
}
}
}
- BFS(DFS)算有多少个连通块
st[][]
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
{
if(!st[i][j] && g[i][j] == '@')
{
bfs(i, j);
cnt ++
}
}
}
- 求树的直径(树中两点的最大长度)
思路:任意取一个点x,找到一个点y,距离x最远;再找距离y最远的点,这个最远的距离就是树的直径。(可以用反证法证明)
上面这种方法树的边权一定要都为正数 - 图的存储方式
邻接矩阵
邻接表(每个节点都开一个单链表,存的是这个节点可以到的所有点)
// 邻接表的存储方式
// h存储的是头节点的值,e存储的是节点的值,ne存储下一个节点的值,w存储边的权值
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
// 遍历
for(int i = h[u]; ~i; i = ne[i])
{
//
}
- 最大公约数
gcd(a, b) = gcd(b, a % b)
用a mod b = a - (a / b) * b
证明
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
数论知识:
质因数分解、线性筛质数、约数个数、约数之和、最大公约数、扩展欧几里得
筛法求1~n所有质数O(n)
void get_primes(int n)
{
for(int i = 2; i <= n; i ++ )
{
if(!st[i]) primes[cnt ++] = i;
for(int j = 0; primes[j] <= n / i; j ++ )
{
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
扩展欧几里得算法:
gcd(a, b) = d, 求x、y使ax + by = d
int exgcd(int a, int b, int &x, int &y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
int x1, y1;
int d = exgcd(b, a % b, x1, y1);
x = y1, y = x1 - (a / b) * y1;
}
- 最短路几个算法
dijkstra算法: 有一个集合S是最小值确定的点,每次剩下的点中找出距离最小的点,将这个点加入集合S,用这个点来更新其他所有的点。(边权不能为负)O(n^2)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510, M = 100010, INF = 0x3f3f3f3f;
int dist[N], g[N][N];
bool st[N];
int n, m;
void dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for(int i = 0; i < n; i ++ )
{
int t = -1;
for(int j = 1; j <= n; j ++ )
if(!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
st[t] = true;
for(int j = 1; j <= n; j ++ )
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
int main()
{
cin >> n >> m;
memset(g, 0x3f, sizeof g);
while (m -- )
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
if(x == y) g[x][y] = 0;
else g[x][y] = min(g[x][y], z);
}
dijkstra();
if(dist[n] == 0x3f3f3f3f) puts("-1");
else printf("%d", dist[n]);
return 0;
}
bellman-ford算法:有边数限制的最短路算法,用边来更新,dist[b] = min(dist[b], dist[a] + w[a][b])
O(nm)
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510, M = 100010, INF = 0x3f3f3f3f;
int dist[N], backup[N];
struct edge
{
int a, b, w;
}Edge[M];
int n, m, k;
void bellman_ford()
{
memset(dist, 0x3f3f3f3f, sizeof dist);
dist[1] = 0;
for(int i = 0; i < k; i ++ )
{
memcpy(backup, dist, sizeof dist);
for(int j = 0; j < m; j ++ )
{
int a = Edge[j].a, b = Edge[j].b, w = Edge[j].w;
dist[b] = min(dist[b], backup[a] + w);
}
}
}
int main()
{
cin >> n >> m >> k;
for(int i = 0; i < m; i ++ )
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
Edge[i] = {x, y, z};
}
bellman_ford();
if(dist[n] > INF / 2) puts("impossible");
else printf("%d", dist[n]);
return 0;
}
spfa算法:是对belllman_ford算法的优化,dist[b] = min(dist[b], dist[a] + w[a][b])
,只有dist[a]变小了才用a更新b,用宽搜来优化,O(n)~O(nm)
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N = 100010, INF = 0x3f3f3f3f;
int h[N], e[N], ne[N], w[N], idx;
int dist[N];
bool st[N];
int n, m;
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
void spfa()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
queue<int> q;
q.push(1);
st[1] = true;
while(q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for(int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if(!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
while(m --)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
}
spfa();
if(dist[n] > INF / 2) puts("impossible");
else printf("%d", dist[n]);
return 0;
}
floyd算法:多源最短路,基于动态规划f[i][j] = min(f[i][j], f[i][k] + f[k][j])
,O(n^3)
#include <iostream>
#include <cstring>
using namespace std;
const int N = 210, INF = 0x3f3f3f3f;
int f[N][N];
int main()
{
int n, m, k;
cin >> n >> m >> k;
memset(f, 0x3f, sizeof f);
for(int i = 1; i <= n; i ++ ) f[i][i] = 0;
while (m -- )
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
f[x][y] = min(f[x][y], z);
}
for(int k = 1; k <= n; k ++ )
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ )
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
while(k --)
{
int a, b;
scanf("%d%d", &a, &b);
if(f[a][b] > INF / 2) puts("impossible");
else printf("%d\n", f[a][b]);
}
return 0;
}