目录
最短路问题
存图:链式前向星
静态建立的邻接表,时间、空间、遍历效率均为O(m)。
struct edge {
int next, to, weight;
} e[MAX];
int head[MAX], dis[MAX], vis[MAX];
int cnt;
void add(int u, int v, int w) {
e[++cnt].next = head[u];
e[cnt].to = v;
e[cnt].weight = w;
head[u] = cnt;
}
遍历循环条件(按节点遍历以该点为起点的所有边)
for (int i = head[x]; i; i = e[i].next)
距离交换条件
if (dis[e[i].to] > dis[x] + e[i].weight)
最短路问题(超详细~~)_DearLife丶的博客-CSDN博客_最短路问题
无论题意怎么写,最好都处理掉重边情况
算法名称 时间复杂度(最好) 时间复杂度(最坏) 空间复杂度 用途
Dijkstra O(N^2) O(N^2) O(N) 单源
SPFA(不稳定) O(KM) O(NM) O(N) 单源
Floyd O(N^3) O(N^3) O(N^2) 多源
Dijkstra算法
for (int j = 1; j <= n; j ++ )
if (!vis[j] && (t == -1 || dis[t] > dis[j]))
t = j;
遍历找到当前最短节点t
vis[t]=1;
for (int j = 1; j <= n; j ++ )
dis[j] = min(dis[j], dis[t] + e[t][j]);
根据t更新dis
Dijkstra算法(堆优化)
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;
小顶堆,pair先根据first比较,相同时比较second
简化:typedef pair<int,int> p;
while (!q.empty()) { 遍历
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = head[x]; i; i = e[i].next) {
if (dis[e[i].to] > dis[x] + e[i].weight) {
dis[e[i].to] = dis[x] + e[i].weight;
q.push({dis[e[i].to], e[i].to}); 每次更新dis就放入堆中
}
}
}
SPFA算法(已死,存在负权时使用)
bool SPFA() {
std::queue<int>q;
q.push(1); 1为源点,若无源点就将全部点放入,不初始化dis数组
dis[1] = 0;
while (!q.empty()) {
int x = q.front();
q.pop();
vis[x] = 0;
for (int i = 0; i < e[x].size(); i++) {
int vv = e[x][i].first, ww = e[x][i].second;
if (dis[vv] > dis[x] + ww) {
dis[vv] = dis[x] + ww;
cnt[vv] = cnt[x] + 1;
if (cnt[vv] >= n) {
return 1;
}
if (!vis[vv]) {
q.push(vv);
vis[vv] = 1;
}
}
}
}
return 0;
}
Floyd算法(最多处理500个点左右,往上秒炸)
void Floyd() {
for (int k = 1; k <= n; k ++ )
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}三重循环更新各个点之间距离
KMP
写不出来就背
void get_next() {
int i = 0, j = -1;
int len = strlen(mo);
next[i] = j;
while (i < len) {
while (j != -1 && mo[i] != mo[j]) {
j = next[j];
}
next[++i] = ++j;
}
}
int count() {
int i = 0, j = 0, n = 0;
int lenm = strlen(mo), lens = strlen(str);
while (i < lens) {
while (j != -1 && mo[j] != str[i]) {
j = next[j];
}
++i;
++j;
if (j == lenm){
++n;
j=0;(看情况是否归零)
}
}
return n;
}
next数组的周期性
1.如果i % ( i - next[i] ) == 0, 则字符串 1~ i - next[i]为其最小的循环节。并且此字符串的循环节个数最多为 i / (i - next[i]);
2.如果 i - next[?]能够得到 i % (i - next[?]) == 0, 则 i - next[?]也为其循环节,但不是最小的循环节。此循环节的个数为 i / (i - next[?]);
3.如果 i % (i - next[i]) != 0, 则此字符串不存在能够组成完整字符串的循环节。
4.next[i]存在,循环节未必存在: 如 abcabcab中,next[8] = 5, 但是对于i而言不存在循环节。但是 i - next[i]必为重复的,只是最后的一段无法完全满足条件。8 -5 == 3, 所以为abc,abc不断循环。