[图论]最短路系列

昨天今天两天复习了一下最短路,

1 Floyd
2 Dijkstra
3 Bellman-ford
4 (SPFA)

(但是还有一些其他的比如:第k短路,Johnson,差分约束没有仔细研究过)


Dijkstra堆优化

luogu3371

题目描述

如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。

输入输出格式

输入格式:

第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。

接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。

输出格式:

一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)

说明

时空限制:1000ms,128M

对于100%的数据:N<=10000,M<=500000

#include<bits/stdc++.h>
using namespace std;
const int INF = 2147483647;
int n,m,s,d[10035];
struct NODE
{
    int y,val;
    NODE(int a, int b):y(a), val(b) {}
};
vector<NODE> mp[10035];
struct cmp
{
    bool operator() (int &a, int &b) const
    {
        return d[a] > d[b];
    }
};
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    priority_queue<int, vector<int>, cmp> q;
    for (int i=1; i<=n; i++)d[i] = INF;
    d[s] = 0;
    for (int i=1; i<=m; i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        mp[x].push_back(NODE(y, z));
    }
    q.push(s);
    while (!q.empty())
    {
        int tt = q.top();q.pop();
        for (int i=0; i<mp[tt].size(); i++)
        {
            if (d[mp[tt][i].y] > d[tt] + mp[tt][i].val)
            {
                d[mp[tt][i].y] = d[tt] + mp[tt][i].val;
                q.push(mp[tt][i].y);
            }
        }
    }
    for (int i=1; i<=n; i++)printf("%d ",d[i]);
    return 0;
}

luogu2384

题目描述

给定n个点的带权有向图,求从1到n的路径中边权之积最小的简单路径。

输入输出格式

输入格式:

第一行读入两个整数n,m,表示共n个点m条边。 接下来m行,每行三个正整数x,y,z,表示点x到点y有一条边权为z的边。

输出格式:

输出仅包括一行,记为所求路径的边权之积

对于100%的数据,n<=1000,m<=1000000。边权不超过10000。

#include<bits/stdc++.h>
using namespace std;
const int N = 1003;
int n,m;
long long d[N];
struct NODE
{
    int y;
    long long val;
    NODE(long long a, long long b):y(a),val(b) {}
};
struct cmp
{
    bool operator () (int &a, int &b)const
    {
        return d[a] > d[b];
    }
};
vector<NODE>mp[N];
priority_queue<int, vector<int>, cmp> q;
int main()
{
    memset(d, 0x3f3f3f3f, sizeof(d));
    d[1] = 1;
    scanf("%d%d",&n,&m);
    for (int i=1; i<=m; i++)
    {
        int x, y;long long z;
        scanf("%d%d%lld",&x,&y,&z);
        mp[x].push_back(NODE(y, z));
    }
    q.push(1);
    while (!q.empty())
    {
        int tt = q.top();q.pop();
        for (int i=0; i<mp[tt].size(); i++)
        {
            if (d[mp[tt][i].y] > d[tt]*mp[tt][i].val)
            {
                d[mp[tt][i].y] = d[tt]*mp[tt][i].val;
                q.push(mp[tt][i].y);
            }
        }
    }
    printf("%lld\n",d[n]%9987);
    return 0;
}

普通Bellman-ford

luogu2136(求负权环)

题目描述

在小明和小红的生活中,有N个关键的节点。有M个事件,记为一个三元组(Si,Ti,Wi),表示从节点Si有一个事件可以转移到Ti,事件的效果就是使他们之间的距离减少Wi。

这些节点构成了一个网络,其中节点1和N是特殊的,节点1代表小明,节点N代表小红,其他代表进展的阶段。所有事件可以自由选择是否进行,但每次只能进行当前节点邻接的。请你帮他们写一个程序,计算出他们之间可能的最短距离。

对于全部数据,N<=1000,M<=10000,|Wi|<=100,保证从节点1到N有路径。

#include<bits/stdc++.h>
using namespace std;
const int M = 10035;
const int N = 1003;
int u[M],v[M],w[M],d[N],n,m,ans = 1e9;
bool vis[N];
inline bool BELL(int x)
{
    memset(d, 0x3f3f3f3f, sizeof(d));
    d[x] = 0;
    for (int k=1; k<n; k++)
    {
        bool fs = 1;
        for (int i=1; i<=m; i++)
            if (d[v[i]] > d[u[i]] + w[i])
            {
                d[v[i]] = d[u[i]] + w[i];
                fs = 0;
            }
        if (fs)break;
    }
    bool fl = 0;
    for (int i=1; i<=m; i++)
        if (d[v[i]] > d[u[i]] + w[i]){fl = 1; break;}
    ans = min(ans, d[n-x+1]);
    return fl;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1; i<=m; i++)scanf("%d%d%d",&u[i],&v[i],&w[i]),w[i] = -w[i];
    bool f1 = BELL(1);
    bool f2 = BELL(n);
    if (f1||f2)puts("Forever love");
    else printf("%d\n",ans);
    return 0;
}

bfs-SPFA(负权环)

luogu2850

题目描述

While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ‘s farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..N, M (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.

As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .

To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.

John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John的每个农场有M条小路(无向边)连接着N (从1..N标号)块地,并有W个虫洞。其中1<=N<=500,1<=M<=2500,1<=W<=200。 现在John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。 John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有虫洞回帮你回到超过10000秒以前。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 503;
 4 const int M = 6003;
 5 struct NODE
 6 {
 7     int y,val;
 8     NODE(int a, int b):y(a),val(b) {}
 9 };
10 int n,m,tt,w,d[N],cnt[N];
11 bool vis[N],iq[N];
12 vector<NODE> mp[N];
13 deque<int> q;
14 inline int left()
15 {
16     for (int i=1; i<=n; i++)if (!vis[i])return i;
17     return 0;
18 }
19 inline void clear(deque<int> &q)
20 {
21     deque<int> emt;
22     swap(q, emt);
23     return;
24 }
25 int main()
26 {
27     scanf("%d",&tt);
28     while (tt--)
29     {
30         scanf("%d%d%d",&n,&m,&w);
31         memset(vis, 0, sizeof(vis));
32         memset(d, 0, sizeof(d));
33         memset(mp, 0, sizeof(mp));
34         for (int i=1; i<=m; i++)
35         {
36             int x,y,z;
37             scanf("%d%d%d",&x,&y,&z);
38             mp[x].push_back(NODE(y, z));
39             mp[y].push_back(NODE(x, z));
40         }
41         for (int i=1; i<=w; i++)
42         {
43             int x,y,z;
44             scanf("%d%d%d",&x,&y,&z);
45             mp[x].push_back(NODE(y, -z));
46         }
47         int s;
48         bool fk = 0;
49         while (s = left())
50         {
51             clear(q);//printf("#%d:\n",s);
52             memset(iq, 0, sizeof(iq));
53             memset(cnt, 0, sizeof(cnt));
54             memset(d, 0x3f3f3f3f, sizeof(d));
55             q.push_back(s);
56             iq[s] = 1;vis[s] = 1;fk = 0;
57             d[s] = 0;
58             while (!q.empty())
59             {
60                 int tt = q.front();q.pop_front();
61                 iq[tt] = 0;cnt[tt]++;//printf("@@%dout\n",tt);
62                 if (cnt[tt] == n+1){fk = 1;break;}
63                 for (int i=0; i<mp[tt].size(); i++)
64                 {
65                     vis[mp[tt][i].y] = 1;
66                     if (d[mp[tt][i].y] > d[tt] + mp[tt][i].val)
67                     {
68                         d[mp[tt][i].y] = d[tt] + mp[tt][i].val;
69                         if (!iq[mp[tt][i].y])
70                         {
71                             iq[mp[tt][i].y] = 1;//printf("@%dpush\n",mp[tt][i].y);
72                             if (q.empty())q.push_back(mp[tt][i].y);
73                             else{
74                                 if (d[q.front()] > d[mp[tt][i].y])
75                                     q.push_front(mp[tt][i].y);
76                                 else q.push_back(mp[tt][i].y);
77                             }
78                         }
79                     }
80                 }
81             }
82             if (fk)break;
83         }
84         if (fk)puts("YES");
85         else puts("NO");
86     }
87     return 0;
88 }

或者,bfs-SPFA有一种小优化。将dis数组初始化为0,再将vis数组的更新放进dis[]与mp[]的松弛里。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 503;
 4 const int M = 6003;
 5 struct NODE
 6 {
 7     int y,val;
 8     NODE(int a, int b):y(a),val(b) {}
 9 };
10 int n,m,tt,w,d[N],cnt[N];
11 bool vis[N],iq[N];
12 vector<NODE> mp[N];
13 deque<int> q;
14 inline int left()
15 {
16     for (int i=1; i<=n; i++)if (!vis[i])return i;
17     return 0;
18 }
19 inline void clear(deque<int> &q)
20 {
21     deque<int> emt;
22     swap(q, emt);
23     return;
24 }
25 int main()
26 {
27     scanf("%d",&tt);
28     while (tt--)
29     {
30         scanf("%d%d%d",&n,&m,&w);
31         memset(vis, 0, sizeof(vis));
32         memset(d, 0, sizeof(d));
33         memset(mp, 0, sizeof(mp));
34         for (int i=1; i<=m; i++)
35         {
36             int x,y,z;
37             scanf("%d%d%d",&x,&y,&z);
38             mp[x].push_back(NODE(y, z));
39             mp[y].push_back(NODE(x, z));
40         }
41         for (int i=1; i<=w; i++)
42         {
43             int x,y,z;
44             scanf("%d%d%d",&x,&y,&z);
45             mp[x].push_back(NODE(y, -z));
46         }
47         int s;
48         bool fk = 0;
49         while (s = left())
50         {
51             clear(q);
52             memset(iq, 0, sizeof(iq));
53             memset(cnt, 0, sizeof(cnt));
54             memset(d, 0, sizeof(d));
55             q.push_back(s);
56             iq[s] = 1;vis[s] = 1;fk = 0;
57             d[s] = 0;
58             while (!q.empty())
59             {
60                 int tt = q.front();q.pop_front();
61                 iq[tt] = 0;cnt[tt]++;
62                 if (cnt[tt] == n+1){fk = 1;break;}
63                 for (int i=0; i<mp[tt].size(); i++)
64                 {
65                     if (d[mp[tt][i].y] > d[tt] + mp[tt][i].val)
66                     {
67                         d[mp[tt][i].y] = d[tt] + mp[tt][i].val;vis[mp[tt][i].y] = 1;
68                         if (!iq[mp[tt][i].y])
69                         {
70                             iq[mp[tt][i].y] = 1;
71                             if (q.empty())q.push_back(mp[tt][i].y);
72                             else{
73                                 if (d[q.front()] > d[mp[tt][i].y])
74                                     q.push_front(mp[tt][i].y);
75                                 else q.push_back(mp[tt][i].y);
76                             }
77                         }
78                     }
79                 }
80             }
81             if (fk)break;
82         }
83         if (fk)puts("YES");
84         else puts("NO");
85     }
86     return 0;
87 }

bfs-SPFA2


dfs-SPFA(负权环)

luogu3385

输入输出格式

输入格式:

第一行一个正整数T表示数据组数,对于每组数据:

第一行两个正整数N M,表示图有N个顶点,M条边

接下来M行,每行三个整数a b w,表示a->b有一条权值为w的边(若w<0则为单向,否则双向)

输出格式:

共T行。对于每组数据,存在负环则输出一行"YE5"(不含引号),否则输出一行"N0"(不含引号)。

说明

N,M,|w|≤200 000;1≤a,b≤N;T≤10 此题普通Bellman-Ford或BFS-SPFA会TLE

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 struct NODE
 4 {
 5     int y,val;
 6     NODE(int a, int b):y(a),val(b) {}
 7 };
 8 const int N = 200355;
 9 const int M = 200355;
10 vector<NODE>mp[N];
11 int n,m,tt,d[N];
12 bool vis[N],done;
13 inline void init()
14 {
15     memset(vis, 0, sizeof(vis));
16     memset(d, 0, sizeof(d));
17     for (int i=1; i<=n; i++)mp[i].clear();
18     done = 0;
19     scanf("%d%d",&n,&m);
20     for (int i=1; i<=m; i++)
21     {
22         int x,y,z;
23         scanf("%d%d%d",&x,&y,&z);
24         mp[x].push_back(NODE(y, z));
25         if (z>=0) mp[y].push_back(NODE(x, z));
26     }
27     return;
28 }
29 inline void SPFA(int x)
30 {
31     vis[x] = 1;
32     for (int i=0; i<mp[x].size(); i++)
33     {
34         int u = x, v = mp[x][i].y, w = mp[x][i].val;
35         if (d[u] + w < d[v]){
36             if (vis[v]){done = 1;return;}
37             d[v] = d[u] + w;
38             SPFA(v);
39         }
40     }
41     vis[x] = 0;
42     return;
43 }
44 int main()
45 {
46     scanf("%d",&tt);
47     while (tt--)
48     {
49          init();
50          for (int i=1; i<=n; i++)
51          {
52              if (!vis[i])SPFA(i);
53              if (done)break;
54          }
55          if (done)puts("YE5");
56          else puts("N0");
57     }
58     return 0;
59 }

这一题我的bfs-SPFA就是卡不过去……学习了一发dfs-SPFA。

理解也不是很难。由于bfs主要用于扩展最短路,而dfs可以更快地找到负环。


SPFA(最短路)

luogu2951

题目描述

Bessie is playing hide and seek (a game in which a number of players hide and a single player (the seeker) attempts to find them after which various penalties and rewards are assessed; much fun usually ensues).

She is trying to figure out in which of N (2 <= N <= 20,000) barns conveniently numbered 1..N she should hide. She knows that FJ (the seeker) starts out in barn 1. All the barns are connected by M (1 <= M <= 50,000) bidirectional paths with endpoints A_i and B_i (1 <= A_i <= N; 1 <= B_i <= N; A_i != B_i); it is possible to reach any barn from any other through the paths.

Bessie decides that it will be safest to hide in the barn that has the greatest distance from barn 1 (the distance between two barns is the smallest number of paths that one must traverse to get from one to the other). Help Bessie figure out the best barn in which to hide.

奶牛贝西和农夫约翰(FJ)玩捉迷藏,现在有N个谷仓,FJ开始在第一个谷仓,贝西为了不让FJ找到她,当然要藏在距离第一个谷仓最远的那个谷仓了。现在告诉你N个谷仓,和M个两两谷仓间的“无向边”。每两个仓谷间当然会有最短路径,现在要求距离第一个谷仓(FJ那里)最远的谷仓是哪个(所谓最远就是距离第一个谷仓最大的最短路径)?如有多个则输出编号最小的。以及求这最远距离是多少,和有几个这样的谷仓距离第一个谷仓那么远。

输入输出格式

输入格式:

* Line 1: Two space-separated integers: N and M

* Lines 2..M+1: Line i+1 contains the endpoints for path i: A_i and B_i

第一行:两个整数N,M;

第2-M+1行:每行两个整数,表示端点A_i 和 B_i 间有一条无向边。

输出格式:

* Line 1: On a single line, print three space-separated integers: the index of the barn farthest from barn 1 (if there are multiple such barns, print the smallest such index), the smallest number of paths needed to reach this barn from barn 1, and the number of barns with this number of paths.

仅一行,三个整数,两两中间空格隔开。表示:距离第一个谷仓最远的谷仓编号(如有多个则输出编号最小的。),以及最远的距离,和有几个谷仓距离第一个谷仓那么远。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 20035;
 4 const int M = 50035;
 5 int n,m,d[N];
 6 bool vis[N];
 7 vector<int>mp[N];
 8 queue<int>q;
 9 int main()
10 {
11     scanf("%d%d",&n,&m);
12     for (int i=1; i<=m; i++)
13     {
14         int x,y;
15         scanf("%d%d",&x,&y);
16         mp[x].push_back(y);
17         mp[y].push_back(x);
18     }
19     memset(d, 0x3f3f3f3f, sizeof(d));
20     d[1] = 0;
21     q.push(1);
22     while (q.size())
23     {
24         int tt = q.front();q.pop();
25         vis[tt] = 0;
26         for (int i=0; i<mp[tt].size(); i++)
27             if (d[tt] + 1 < d[mp[tt][i]])
28             {
29                 d[mp[tt][i]] = d[tt] + 1;
30                 if (!vis[mp[tt][i]]){
31                     q.push(mp[tt][i]);
32                     vis[tt] = 1;
33                 }
34             }
35     }
36     int lb, mn = *max_element(d+1, d+n+1), cnt = 0;
37     for (int i=n; i>=1; i--)
38         if (d[i] == mn){cnt++;lb = i;}
39     printf("%d %d %d",lb,mn,cnt);
40     return 0;
41 }

原文地址:https://www.cnblogs.com/antiquality/p/8525081.html

时间: 2024-10-08 20:40:42

[图论]最短路系列的相关文章

bzoj4144 [AMPPZ2014]Petrol 图论 最短路 并查集

bzoj4144 [AMPPZ2014]Petrol 图论 最短路 并查集 1.这道题我们主要就是要求出距离一个油站的最近的油站 首先我们dijkstra 求出任意一个点到 离他最近的油站的距离 2.然后会发现 如果一条边的两个端点 的最近油站不同的话 那么这条边就会在这两个油站的最短路上 3.然后对于每一条边 我们将他的权值 变为 dis[ u ] + dis[ v ] + e[ i ][ j ] 如果u与v最近油站相同 那么这个无意义 如果不同 那么久表示 u 最近油站 到 v 最近油站的最

POJ 3259 Wormholes (图论---最短路 Bellman-Ford || SPFA)

链接:http://poj.org/problem?id=3259 Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BE

HDU 5521 [图论][最短路][建图灵感]

/* 思前想后 还是决定坚持写博客吧... 题意: n个点,m个集合.每个集合里边的点是联通的且任意两点之间有一条dis[i]的边(每个集合一个dis[i]) 求同时从第1个点和第n个点出发的两个人相遇的最短时间,并输出相遇的地点,如果有多个按编号大小顺序输出. 输入: 测试数据 t n m 以下m行每行 dis[i] 该集合点的数量 ...每个点的标号 数据范围: n 2-1e5 所有集合的元素的数量和 1e6 思路: 如果直接跑最短路,边会存爆的. 考虑换种思路建边. 每个集合看作两个点,一

图论 最短路 基础

图论基础 , 最短路 图的简单概念 顶点 (Vertex), 边 (Edge) 有向图 , 无向图 , 无向图是一种特殊的有向图 度,有向图分为出度 和 入度,无向图的度,代表 连出去的边 顶点和边都可以具有属性,称为权重,顶点称为 点权,边 称为 边权 稠密图 边很多,大约是 顶点的平方 稀疏图 边很少 , 重边(平行边),自环, 路径:从一给顶点到达另一个顶点称为一条路径 路径中边的数量称为路径长度,如果路径中的顶点均不重复,称为简单路径 如果路径中的第一个顶点 \(v_i\) 和最后一个顶

洛谷P1027 Car的旅行路线 计算几何 图论最短路

题意 求某城到某城的最小花费 一个城中有四个机场,一个城中的机场相互可达,用公路到达,但是不同城的公路的单位路程的费不同,两个不同城的机场(我不知道相同城可不可以)可以通过机场到达,且飞机单位路程价格一定,问从 a 城到b城的最小花费,可从a的任一机场出发,从 b 的任一机场结束 . 题解 这道题思路还算容易,就是求最短路,只是建图比较麻烦, 总体思路 1.建图(1) 相同城 的四个机场两两连线 求距离, [1]但是他只给出了三个点,也就是说这第四个点要我们自己求 首先他给出三个点,这三个点一定

图论——最短路

Tyvj 1221 微子危机——战略 背景 №.3Summer联盟战前兵力战略转移. 描述 Summer的兵力分布在各个星球上,现在需要把他们全部转移到某个星球上.Summer一共拥有N个星球(1-N),你要把这N个星球上的兵力转到第M个星球上.本来每个星球之间都有星际轨道连接,但Guiolk监视了某些轨道,我们一但走上这些轨道,有可能受到他的攻击.为了安全,Summer不会走被监视的轨道.于是,只有L个星际轨道是被批准通过的.Summer的国防部想统计一下所需的最短路程(即每个星球到第M星球的

图论——最短路②

RT 最短路计数 给出一个N个顶点M条边的无向无权图,顶点编号为1-N.问从顶点1开始,到其他每个点的最短路有几条. 输入输出格式 输入格式: 输入第一行包含2个正整数N,M,为图的顶点数与边数. 接下来M行,每行两个正整数x, y,表示有一条顶点x连向顶点y的边,请注意可能有自环与重边. 输出格式: 输出包括N行,每行一个非负整数,第i行输出从顶点1到顶点i有多少条不同的最短路,由于答案有可能会很大,你只需要输出mod 100003后的结果即可.如果无法到达顶点i则输出0. 样例 输入: 输出

图论——最短路①

RT 找工就业 Bessie is running out of money and is searching for jobs. Farmer John knows this and wants the cows to travel around so he has imposed a rule that his cows can only make D (1 <= D <= 1,000) dollars in a city before they must work in another

[图论][最短路]步行

题目描述 ftiasch又开发了一个奇怪的游戏,这个游戏是这样的:有N个格子排成一列,每个格子上有一个数字,第i个格子的数字记为Ai.这个游戏有2种操作:1.如果现在在第i个格子,则可以跳到第Ai个格子.2.把某个Ai增加或减少1.nm开始在第1个格子,他需要走到第N个格子才能通关.现在他已经头昏脑涨啦,需要你帮助他求出,从起点到终点最少需要多少次操作. 输入 第1行,1个整数N.第2行,N个整数Ai. 输出 第1行,1个整数,表示最少的操作次数. 样例输入 5 3 4 2 5 3 样例输出 3