原题链接

解题思路

这题用\(SPFA\)会被卡,所以我们不能用\(SPFA\)

但是观察数据我们可以发现对于道路,\(0≤C_i≤10^{5}\)

所以对于每个连通块(内部不存在航线),我们可以用\(Dijkstra\)算法进行求解,因为不存在负权边,而\(Dijkstra\)算法的时间较为稳定,所以对于连通块内部的最短路,我们采用\(Dijkstra\)

块内问题解决了,但是块间呢

保证如果有一条航线可以从\(A_i\) 到 \(B_i\),那么保证不可能通过一些道路和航线从 \(B_i\) 回到 \(A_i\)。

我们将每个连通块看做一个大点

那么根据上述性质,我们可以得到这张由大点为点,航线为边的图是一张拓扑图\((DAG)\)

那么\(DAG\)的最短路我们可以按照它的拓扑序扫描求出最短路

为什么呢

因为我们利用拓扑序进行\(DP\),那后来的节点一定是无法更新前面的节点,这样就可以确保无后效性,因此可以正确求出最短路

解题步骤

1.先输入所有的双向道路,然后用\(dfs\)求出所有的连通块,用\(id[]\)数组统计每个数所在的连通块编号,用一个\(vector\)<\(int\)> \(block[]\)来保存每个编号的连通块里存的点

2.输入所有的航线,再输入的同时可以统计每个连通块的入度

3.拓扑排序

4.按照拓扑序对每个连通块进行\(Dijkstra\)算法

5.\(Dijkstra\)步骤:

(1)每次从堆中取出一个点\(t\)

(2)遍历\(t\)的所有出边,同一个连通块的进行松弛操作,不同连通块的将对方连通块入度\(-1\),如果\(-1\)后连通块的入度为0,插入拓扑序队列中(所以拓扑序的队列要开成全局的)

代码

#include <iostream>
#include <vector>
#include <cstring>
#include <queue> using namespace std;
typedef pair<int, int> PII; const int N = 25010, M = 2e5 + 10, INF = 0x3f3f3f3f;
int h[N], e[M], w[M], ne[M], idx;
int dist[N], id[N], st[N], din[N];
int n, mr, mp, S, bcnt; vector<int> block[M];
queue<int> q; void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
} void dfs(int u, int bid)
{
id[u] = bid, block[bid].push_back(u); for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (!id[j]) dfs(j, bid);
}
} void Dijkstra(int bid)
{
priority_queue<PII, vector<PII>, greater<> > heap; for (auto u : block[bid])
heap.push({dist[u], u}); while (heap.size())
{
auto t = heap.top().second; heap.pop(); if (st[t]) continue ;
st[t] = true ; for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if (id[j] == id[t]) heap.push({dist[j], j});
} if (id[j] != id[t] && -- din[id[j]] == 0) q.push(id[j]);
}
}
} void topsort()
{
memset(dist, 0x3f, sizeof dist);
dist[S] = 0; for (int i = 1; i <= bcnt; i ++ )
if (!din[i]) q.push(i); while (q.size())
{
int t = q.front(); q.pop();
Dijkstra(t);
}
} int main()
{
scanf("%d%d%d%d", &n, &mr, &mp, &S); memset(h, -1, sizeof h);
memset(st, 0, sizeof st); while (mr -- )
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w), add(v, u, w);
} for (int i = 1; i <= n; i ++ )
if (!id[i]) dfs(i, ++ bcnt); while (mp -- )
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w), din[id[v]] ++ ;
} topsort(); for (int i = 1; i <= n; i ++ )
if (dist[i] > INF / 2) puts("NO PATH");
else printf("%d\n", dist[i]); return 0;
}

AcWing342. 道路与航线的更多相关文章

  1. 2200: [Usaco2011 Jan]道路和航线 (拓扑排序+dijstra)

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  2. BZOJ 2200--[Usaco2011 Jan]道路和航线(最短路&拓扑排序)

    2200: [Usaco2011 Jan]道路和航线 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1128  Solved: 414[Submit] ...

  3. BZOJ2200 道路和航线【好题】【dfs】【最短路】【缩点】

    2200: [Usaco2011 Jan]道路和航线 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1384  Solved: 508[Submit] ...

  4. [BZOJ 2200][Usaco2011 Jan]道路和航线 spfa+SLF优化

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  5. bzoj2200道路和航线

    试题描述 Farmer John 正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到 T (1≤T≤2.5×10^4)个城镇 ,编号为 1 到 T.这些城镇之间通过 R 条道路(编号为 1 ...

  6. bzoj 2200: [Usaco2011 Jan]道路和航线——拓扑+dijkstra

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  7. [Usaco2011 Jan]道路和航线

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  8. BZOJ 2200: [Usaco2011 Jan]道路和航线

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  9. BZOJ 2200 道路与航线(图论)

    BZOJ 2200 道路与航线 题目大意 有两种路,一种没负数,一种没环,求单源最短路. solution 存在负边权Dij一定不能用嘛,显然不是 根据题意能看出来是tarjan,将双向边缩点,得到的 ...

  10. BZOJ2200 道路与航线 题解

    题目 Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 \((1 <= T <= 25,000)\),编号为\(1T\).这些城镇之间通过\(R ...

随机推荐

  1. NSIS检测并统计字符串中某个字符个数

    !include "LogicLib.nsh" OutFile "检查找字符串中c出现的次数.exe" Name "test" Sectio ...

  2. 220702 T1 玩具 (图的同构,全排列判定)

    [题目描述] Tom和Jerry各有一个玩具,每个玩具都是由M根绳子连接到N个球上制成的. 在Tom的玩具中,球的编号为1,-,N,第i条绳子将球Ai和Bi连接起来. 类似地,在Jerry的玩具中,球 ...

  3. 《吐血整理》高级系列教程-吃透Fiddler抓包教程(29)-Fiddler如何抓取Android7.0以上的Https包-终篇

    1.简介 上一篇宏哥介绍的Xposed是一款可以在不修改APK的情况下影响程序运行的框架.可以编写并加载自己编写的插件app,实现对目标apk的注入.拦截等.一般研究移动安全的都会使用Xposed. ...

  4. 用 VS Code 搞 Qt6:信号、槽,以及QObject

    Qt 里面的信号(Signal)和槽(Slot)虽然看着像事件,但它实际上是用来在两个对象之间进行通信的.既然是通信,就会有发送者和接收者. 1.信号是发送者,触发时通过特有的关键字"emi ...

  5. Scrapy 如何传递 get请求的params

    我们都知道 在requests中可以使用 requests.get(url,params)的方式传值 那么在scrapy中如何传值呢 直接看代码 from urllib.parse import ur ...

  6. 对于python中“FileNotFoundError: [Errno 2] No such file or directory”的解决办法

    在我们使用vscode运行Python代码时遇到的情况 一.出现原因:这里是由于Vscode中,python里的路径是相对与工作目录来进行定位的.所以在多级目录情况下,若不设置绝对路径,往往找不到相应 ...

  7. 京东云开发者|mysql基于binlake同步ES积压解决方案

    1 背景与目标 1.1 背景 国际财务泰国每月月初账单任务生成,或者重算账单数据,数据同步方案为mysql通过binlake同步ES数据,在同步过程中发现计费事件表,计费结果表均有延迟,ES数据与My ...

  8. 重大发现,AQS加锁机制竟然跟Synchronized有惊人的相似

    在并发多线程的情况下,为了保证数据安全性,一般我们会对数据进行加锁,通常使用Synchronized或者ReentrantLock同步锁.Synchronized是基于JVM实现,而Reentrant ...

  9. 干货,深入剖析ReentrantLock源码,推荐收藏

    ReentrantLock和Synchronized都是Java开发中最常用的锁,与Synchronized这种JVM内置锁不同的是,ReentrantLock提供了更丰富的语义.可以创建公平锁或非公 ...

  10. 嵌入式-C语言基础:指针数组(和数组指针区分开来)

    指针数组:一个数组,若其元素均为指针类型的数据,称为指针数组,指针数组存放的是指针类型的数据,也就是指针数组的每个元素都存放一个地址.下面定义一个指针数组: int * p[4];//[]的优先级是比 ...