题目描述
每天早晨,FJ从家中穿过农场走到牛棚。农场由 N 块农田组成,农田通过 M 条双向道路连接,每条路有一定长度。FJ 的房子在 1 号田,牛棚在 N 号田。没有两块田被多条道路连接,以适当的路径顺序总是能在农场任意一对田间行走。当FJ从一块田走到另一块时,总是以总路长最短的道路顺序来走。
FJ 的牛呢,总是不安好心,决定干扰他每天早晨的计划。它们在 M 条路的某一条上安放一叠稻草堆,使这条路的长度加倍。牛希望选择一条路干扰使得FJ 从家到牛棚的路长增加最多。它们请你设计并告诉它们最大增量是多少。
输入输出格式
输入格式:
第 1 行:两个整数 N, M。
第 2 到 M+1 行:第 i+1 行包含三个整数 A_i, B_i, L_i,A_i 和 B_i 表示道路 i 连接的田的编号,L_i 表示路长。
输出格式:
第 1 行:一个整数,表示通过使某条路加倍而得到的最大增量。
输入样例#1: 复制
5 7 2 1 5 1 3 1 3 2 8 3 5 7 3 4 3 2 4 7 4 5 2
输出样例#1: 复制
2
刚看完第一段以为是一道普通的最短路,看到后面。emmmmm...
同学提醒说是最短路径树,然而并不会那么高深的东西qaq,只能用简单的思想去捣鼓了。
听了别人的想法,Dijksra中,在每次松弛时时记录一下v和他的前驱节点u,这样就能逆向回溯出从x到n的最短路径了。
同时记得区分第一次和之后的Dijkstra,注意只有第一次Dijkstra时记录松弛的路径,以防之后错误修改第一次时记录好的最短路径;
暴力最短路径中每一条倍增所产生的影响,然后取其中的最大值与第一次求差,得出结果。
#include<algorithm> #include<iostream> #include<cstring> #include<queue> using namespace std; const int MAX_V= 205; const int MAX_E= 20000; const int inf= 0x3f3f3f3f; struct ENode { int to; int w; int next; }; ENode Edegs[MAX_E]; int Head[MAX_V], cnt; //cnt: 边计数器; int Dis[MAX_V]; int Front[MAX_V]; //Front[v]: 最短路径中v的前置节点u; pair<int, int> E_double_cost; //连接这两点的边,其权值加倍; bool flag; //flag记录是否为初次求最短路; void Add_Edge_0 (int a, int b, int w) { //有向图建边; ++ cnt; Edegs[cnt].to= b; Edegs[cnt].w= w; Edegs[cnt].next= Head[a]; Head[a]= cnt; } void Add_Edge_1 (int a, int b, int w) { //无向图建边; ++ cnt; Edegs[cnt].to= b; Edegs[cnt].w= w; Edegs[cnt].next= Head[a]; Head[a]= cnt; ++ cnt; Edegs[cnt].to= a; Edegs[cnt].w= w; Edegs[cnt].next= Head[b]; Head[b]= cnt; } struct cmpx { bool operator()(int &a, int &b)const { return Dis[a]- Dis[b]> 0; } }; void Dijkstra(int x) { priority_queue<int, vector<int>, cmpx> q; memset(Dis, inf, sizeof(Dis)); Dis[x]= 0; Front[x]= -1; //x 的前驱节点为-1; q.push(x); while (! q.empty()) { int u= q.top(); q.pop(); for (int k= Head[u]; k!= -1; k= Edegs[k].next ) { int v= Edegs[k].to; if(!flag && u== E_double_cost.first&& v== E_double_cost.second ) { //边E(u->v)的花费被加倍了; if (Dis[v]> Dis[u]+ Edegs[k].w+ Edegs[k].w ) { Dis[v]= Dis[u]+ Edegs[k].w+ Edegs[k].w; q.push(v); } } else { if (Dis[v]> Dis[u]+ Edegs[k].w ) { Dis[v]= Dis[u]+ Edegs[k].w; if (flag) Front[v]= u; q.push(v); } } } } } int main() { int n, m; cin >>n >>m; int a, b, w; cnt= -1; memset(Head, -1, sizeof(Head)); for (int i= 0; i< m; i ++) { cin >>a >>b >>w; Add_Edge_1(a, b, w); } flag= true; Dijkstra(1); flag= false; int tmp= Dis[n]; //第一次时到n的最短路距离; int far= tmp; //保存修改后到n的最短路距离; for (int i= n; i!= 1; i= Front[i] ) { E_double_cost.first= Front[i]; E_double_cost.second= i; Dijkstra(1); far= max(far, Dis[n]); } cout <<far- tmp <<endl; return 0; }