poj 3268 spfa+dijkstra

学完了单源最短路,总结一下。

,spfa是宽搜

spfa

bool spfa(int s) {
	int i, j;
	mem(vis, 0);
	mem(dis, 0x3f);
	mem(times, 0);
	queue<int>q;
	q.push(s);
	dis[s] = 0;
	vis[s] = 1;
	while (q.size()) {
		int i = q.front();
		q.pop();
		vis[i] = false;
		for (j = head[i]; j != -1; j = edge[j].nxt) {
			int t = edge[j].t;
			if (dis[t] > dis[i] + edge[j].w) {
				dis[t] = dis[i] + edge[j].w;
				if (vis[t])continue;
				vis[t] = 1;
				q.push(t);
				if (++times[t] > n)
					return true;
			}
		}
	}
}

dijkstra

dijkstra是贪心,从一个源点出发,每次选中最近的可达点k,加入以求出最短路的集合,以k为中转点,求出到达其他点的最短路。
算法流程大致如下:

struct edge {
    int to, v;
    bool operator<(edge b) const {
        return v > b.v;
    }
} e[maxn << 1];

vector<int> g[maxn];//g[i]存放为邻接i点的边 g[i][j]为第j条边的下标
bool vis[maxn];

void dj_normal(int s) {
    mem(d, 0x3f);
    mem(vis, 0);
    d[s] = 0;

    while (1) {
        int min_dis = 1e9+1;
        int id = -1;
        for (int i = 1; i <= n; i++) {
            if (vis[i])continue;
            if (min_dis > d[i]) {
                min_dis = d[i];
                id = i;
            }
        }
        if (id == -1)
            break;
        vis[id]=1;
        int len = g[id].size();
        for (int j = 0; j < len; j++) {
            edge c = e[g[id][j]];
            if(vis[c.to])continue;
            if (d[c.to] > d[id] + c.v) {
                d[c.to] = d[id] + c.v;
            }
        }


    }
}

优化

每次在集合中加入点,都要耗费O(n)的时间来寻找最小值。我们将每次更新后的距离放进堆(优先队列)内,取出的堆顶元素必是最近的点。
需要注意的是:

  1. 从堆顶取出某点时,堆内可能仍有该点较远距离的数据,舍弃即可
  2. 若某点已在集合内,其距离不会再更新,不必更新到该点的距离
void dj(int s) {
    priority_queue<edge> p;
    edge t;
    mem(d, 0x3f);
    mem(vis, 0);
    t.to = s, t.v = 0;
    d[s] = 0;
    p.push(t);
    while (!p.empty()) {
        t = p.top();
        p.pop();
        if (vis[t.to])continue;//堆内可能出现多次该点
        vis[t.to] = 1;
        int len = g[t.to].size();
        for (int j = 0; j < len; j++) {
            edge c = e[g[t.to][j]];
            if(vis[c.to])continue;
            if (d[c.to] > d[t.to] + c.v) {
                d[c.to] = d[t.to] + c.v;
                if (!vis[c.to]) {
                    c.v = d[c.to];
                    p.push(c);
                }
            }
        }
    }
}

bellman-ford

bool bf() {
	mem(dis, 0x3f);
	int i, j;
	four(i, 1, n - 1) {//升序for循环
		four(j, 0, tot - 1) {
			dis[edge[j].t] = Min(dis[edge[j].t], dis[edge[j].f] + edge[j].w);
		}
	}
	return 1;
}

ac代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned un;
# define inf 0x3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define four(a,b,c) for(a=b;a<=c;a++)
#define fourr(a,b,c) for(a=b;a>=c;a--)
#define maxn (int)1e5+3//边
#define maxm (int)1e3+3//点
int Max(int a, int b);
int Min(int a, int b);
struct edge {
	int w, t,nxt,f;
}edge[maxn];
struct node {
	int id;
	int dis;
};
bool operator<(node a, node b) {
	return a.dis > b.dis;
}
int head[maxm], tot;
void add_edge(int u, int v, int val) {
	edge[tot].t = v;
	edge[tot].w = val;
	edge[tot].nxt = head[u];
	head[u] = tot++;
}
int dis[maxm]; bool vis[maxm]; int n, m, x, times[maxm];
bool bf();
bool spfa(int s);
void dj(int s);
int main() {


	mem(head, -1);
	tot = 0;
	cin >> n >> m >> x;//n个点,m条路,终点x
	int i;
	four(i, 1, m) {
		int u, v, w;
		cin >> u >> v >> w;
		add_edge(u, v, w);
	}
	spfa(x);
	dj(x);
	int ans[maxm], maxx = 0;
	mem(ans, 0);
	four(i, 1, n)
	{
		ans[i] += dis[i];//返回的道路
	}
	four(i, 1, n) {
		if (i == x)continue;
		//dj(i);
		spfa(i);
		ans[i] += dis[x];
		maxx = Max(maxx, ans[i]);
	}

	cout << maxx << endl;
}
void dj(int s)
{
	priority_queue<node>q;
	mem(dis, 0x3f);
	mem(vis, 0);
	node now;
	now.id = s;
	now.dis = 0;
	dis[s] = 0;
	q.push(now);
	while (q.size()) {
		now = q.top(); q.pop();
		int i = now.id, j;
		if (vis[i])continue;
		vis[i] = 1;
		for (j = head[i]; j != -1; j = edge[j].nxt) {
			if (dis[edge[j].t] > dis[i] + edge[j].w) {
				now.dis = dis[edge[j].t] = dis[i] + edge[j].w;
				now.id = edge[j].t;
				q.push(now);
			}
		}
	}
}
bool bf() {
	mem(dis, 0x3f);
	int i, j;
	four(i, 1, n - 1) {//升序for循环
		four(j, 0, tot - 1) {
			dis[edge[j].t] = Min(dis[edge[j].t], dis[edge[j].f] + edge[j].w);
		}
	}
	return 1;
}
bool spfa(int s) {
	int i, j;
	mem(vis, 0);
	mem(dis, 0x3f);
	mem(times, 0);
	queue<int>q;
	q.push(s);
	dis[s] = 0;
	vis[s] = 1;
	while (q.size()) {
		int i = q.front();
		q.pop();
		vis[i] = false;
		for (j = head[i]; j != -1; j = edge[j].nxt) {
			int t = edge[j].t;
			if (dis[t] > dis[i] + edge[j].w) {
				dis[t] = dis[i] + edge[j].w;
				if (vis[t])continue;
				vis[t] = 1;
				q.push(t);
				if (++times[t] > n)
					return true;
			}
		}
	}
}
int Max(int a, int b)
{
	return a > b ? a : b;
}
int Min(int a, int b) {
	return a < b ? a : b;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值