最短路径相信大家都有做过,但是最短路径的升级版删边最短路径相信不是很常见到,今天的这道题便是这样一道题
题目描述:
2018-1-31日晚,出现了百年一遇的超级蓝月,同时,也出现了千年一遇的奇观——hw梦游。
具体的说,hw梦到自己在一个图中,这张图有n个节点,m条带权有向边。此时,hw正在节点1,而教室则在遥远的n节点
hw是很害怕迟到的,于是他想知道1->n的最短路是多少。而因为做梦的人会出现闪现的情况,于是他又想知道,若将任意一条边的权值变为0,从1->n的最短路有多长。
Input:
第一行输入两个整数n,m代表点数和边数。
接下来m行,每行3个整数,代表一条边的起点,终点和边权。
Output:
输出包含两个整数
第一个整数,代表原图中1到n最短路径。
第二个整数,代表原图中将一边边权变为0后的最短路径。
Sample Input:
3 3
1 2 5
2 3 4
1 3 10
Sample Output:
9
0
思路:
看到这道题前半部分时,博主立马就想到了方法,但是交了之后发现为什么不对?原来是题没看清,当做无向图做了。有向图可以直接进行搜索,搜索出最短的路径。
然而第二个部分可就难了,博主最开始想到的是直接搜,但是不用想都知道超时,那该怎么办呢?终于,在学长的帮助下想出了利用原图和反图求出去掉边i-j时的1~i的长度和j~n的长度。在求出最短的即可。
废话不多说,上代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
struct JD {
JD *Next;
int To;
long long Wgt;
JD(void) : Next(NULL) {}
JD(int To, long long Wgt) :
To(To), Wgt(Wgt), Next(NULL) {} //构造节点
};
struct JDHead : JD {
JD *Head;
long long Dist;
void Grow(int To, long long Wgt)
{
if (Head) Next =
Next->Next = new JD(To, Wgt);
else Head =
Next = new JD(To, Wgt);
}
JDHead(void) :
Dist(LLONG_MAX), Head(NULL) {} //建图,Dist代表到这里的最短路径,未求之前标为最大值
} G[MAXN], AntiG[MAXN];
struct Unit {
int u;
long long Dist;
bool operator < (const Unit &x) const
{
return Dist > x.Dist;
} //重载运算符,排序时可变为小根堆
};
inline void Search(JDHead *Graph, int Source)
{
priority_queue<Unit> Travel; //优先队列,并且重载为小根堆,可以先从近的开始
Travel.push( (Unit) { Source, 0 } );
Graph[Source].Dist = 0;
while (!Travel.empty()) {
int From = Travel.top().u;
long long CrtDist = Travel.top().Dist; //当前的距离
Travel.pop();
for (register JD *i = Graph[From].Head;
i; i = i->Next)
if (Graph[From].Dist + i->Wgt <
Graph[i->To].Dist) {
Graph[i->To].Dist = Graph[From].Dist + i->Wgt;
Travel.push( (Unit) { i->To, Graph[i->To].Dist } ); //这里有点广搜的感觉
}
}
}
int main(void)
{
int n, m;
scanf("%d %d", &n, &m);
while (m--) {
int u, v;
long long Wgt;
scanf("%d %d %lld", &u, &v, &Wgt);
G[u].Grow(v, Wgt);
AntiG[v].Grow(u, Wgt); //构造原图和反图
}
Search(G, 1);
Search(AntiG, n);
printf("%lld\n", G[n].Dist);
long long MinDist = G[n].Dist;
for (register int i = 1; i <= n; ++i)
for (register JD *j = G[i].Head; //register计数器
j; j = j->Next)
if (G[i].Dist + AntiG[j->To].Dist < //维护最短距离的值
MinDist)
MinDist =
G[i].Dist + AntiG[j->To].Dist;
printf("%lld\n", MinDist);
return 0;
}