个人ACM入门每周小总结③(最短路,KMP)

目录

最短路问题

KMP

最短路问题

存图:链式前向星

静态建立的邻接表,时间、空间、遍历效率均为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不断循环。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值