蒟蒻复习之-----SPFA,dijkstra

14 篇文章 0 订阅

#蒟蒻复习之-----SPFA,dijkstra#

//好把这个太简单了
//作为复习篇不讲原理


##dijkstra##
//表示很少用,即使他要比spfa稳定
附赠代码

模版题

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

const int maxn = 500000 + 100;
const int inf = 2147483647;
int n,m,root;
struct edge {
	int u,v,w;
	int next;
}e[maxn];
int head[maxn], tot = 0;
struct node {
	int x,val;
	bool operator < (node a) const{
		return val > a.val;
	}
};
priority_queue<node>q;

void add(int u, int v, int w) {
	e[++tot] = (edge){u,v,w,head[u]};
	head[u] = tot;
}

int vis[maxn],d[maxn];

void dijkstra(int x) {
	memset(vis,0,sizeof(vis));
	for(int i = 1; i <= n; i++) d[i] = inf;
	d[x] = 0;
	q.push((node){x,0});
	while(!q.empty()) {
		int k = q.top().x;
		q.pop();
		if(vis[k]) continue;
		vis[k] = 1;
		for(int i = head[k]; i; i = e[i].next) {
			int v = e[i].v;
			if(d[v] > d[k] + e[i].w) {
				d[v] = d[k] + e[i].w;
				q.push((node){v,d[v]});
			}
		}
	}
}

int main() {
	cin>>n>>m>>root;
	for(int i = 1; i <= m; i++) {
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
	}
	dijkstra(root);
	for(int i = 1; i <= n; i++) {
		cout<<d[i]<<' ';
	}
	return 0;
}

##SPFA##
//本萌新最喜欢的算法
//~~~~玄学

SPFA算法是1994年西安交通大学段凡丁提出 %%%%

(同)模版题

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

const int maxn = 500000 + 100;
const int inf = 2147483647;
int n,m,root;
struct edge {
	int u,v,w;
	int next;
}e[maxn];
int head[maxn], tot = 0;

void add(int u, int v, int w) {
	e[++tot] = (edge){u,v,w,head[u]};
	head[u] = tot;
}

int vis[maxn],d[maxn];
void spfa(int x) {
	memset(vis,0,sizeof(vis));
	for(int i = 1; i <= n; i++) d[i] = inf;
	vis[x] = 1, d[x] = 0;
	queue<int>q;
	q.push(x);
	while(!q.empty()) {
		int k = q.front();
		q.pop();
		vis[k] = 0;
		for(int i = head[k]; i; i = e[i].next) {
			int v = e[i].v;
			if(d[v] > d[k] + e[i].w) {
				d[v] = d[k] + e[i].w;
				if(!vis[v]) {
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}	
}

int main() {
	cin>>n>>m>>root;
	for(int i = 1; i <= m; i++) {
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
	}
	spfa(root);
	for(int i = 1; i <= n; i++) {
		cout<<d[i]<<' ';
	}
	return 0;
}

#spfa的用途#

##1.找最短路##
在松弛的同时记录下夫节点
得到的是最短路树(QAQ没啥用)

	while(!q.empty()) {
		int k = q.front();
		q.pop();
		vis[k] = 0;
		for(int i = head[k]; i; i = e[i].next) {
			int v = e[i].v;
			if(d[v] > d[k] + e[i].w) {
				d[v] = d[k] + e[i].w;
				
				f[v] = k;  //hear
				
				if(!vis[v]) {
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}	


	//找父亲 输出u——>v的路径   如果想正输可以建个队列存起来
	do {
    	cout<<v<<' ';
    	v = f[v];
    }while(v != u);
    cout<<u<<' ';

##2.找负环##

spfa最主要的用途之一
一般写dfs版

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 400000 + 100;
int T,n,m;
struct edge {
	int u,v,w;
	int next;
}e[maxn << 1];
int head[maxn],tot = 0;

int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar(); 
	}
	while(ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + ch - '0';
		ch = getchar();
	}
	return x * f;
}

void add(int u, int v, int w) {
	e[++tot] = (edge) {u,v,w,head[u]};
	head[u] = tot;
}

int dis[maxn],vis[maxn],col[maxn],flag;

void spfa(int x) {
	if(flag) return;
	vis[x] = 1;
	for(int i = head[x]; i; i = e[i].next) {
		int v = e[i].v;
		if(dis[v] > dis[x] +e[i].w) {
			dis[v] = dis[x] + e[i].w;
			if(vis[v]) {
				flag = 1;
				return;
			}
			else {
				spfa(v);
			}
		}
	}	
	vis[x] = 0;
	return;
}

int main() {
	T = read();
	while(T--) {
		memset(head,0,sizeof(head));
		memset(e,0,sizeof(e));
		memset(vis,0,sizeof(vis));
		memset(dis,0,sizeof(dis));
		tot = 0, flag = 0;
		n = read(), m = read();
		for(int i = 1; i <= m; i++) {
			int u = read(), v = read(), w = read();
			add(u,v,w);
			if(w >= 0) add(v,u,w);
		}
		for(int i = 1; i <= n; i++) {
			if(!vis[i]) spfa(i);
		}
		if( flag ) {
			puts("YE5");
		}
		else {
			puts("N0");
		}
	}
	return 0;
}

##3.差分约束系统##

差分约束是求解N元一次特殊不等式组的一种方法。
差分约束系统包含N个变量和M个约束条件,每个约束条件都是一个关于两个变量的一次不等式,每个不等式形如X[i]-X[j]<=A[k],其中1<=i,j<=N,1<=k<=M,X[i]、X[j]为变量,A[k]为常数。
引理:若{Xi}为差分约束系统的一组解,Δ为常数,那么{Xi+Δ}也是一组解。

差分约束系统中的每个不等式都与最短路中的三角形不等式 dist[v]<=dist[u]+edge(u,v) 形似。
把变量Xi看做有向图中的点i,对不等式X[i]-X[j]<=A[k]从j向i连一条有向边,边权为A[k]。建立一个源点,向每个点连一条有向边,边权为0。从源点出发求单源最短路,X[i]=dist[i]就是一组可行解。有负环说明无解。
若对X[i]有范围限制,可用X[i]与源点之间的约束表示。
不等式>=号时用最长路解决,此时有正环说明无解。

dwarf tower(SPFA变形)
伊吹萃香(建图)
道路和飞机Roads and Planes(SLF优化)
天路(二分+SPFA)
狡猾的商人(差分约束)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值