UPC 路(最短路方面+路径回溯)

题目描述

Farmer John 热衷于散步,每天早上他都要从 1 号仓库走到 n 号仓库。 Farmer John 家的 n 个仓库被 m 条双向道路连通起来,每条道路有一个长度 w。而Farmer John 又不喜欢走路,所以他走的是从 1 号仓库到 n 号仓库的最短路。
但是 Farmer 的奶牛们总想搞点事情,他们计划着把 m 条道路的其中一条变成原来长度的 2 倍,使得 Farmer John 可能会多走一点路。
他们想知道,最多能让 Farmer John 多走多少路呢?

输入

第一行一个正整数 n,m,表示仓库个数和道路条数。
接下来 m 行,每行三个正整数,表示每条双向道路的连接的仓库和该双向道路的长度。

输出

输出只有一行,表示最多能让 Farmer John 每天早上多走多少路。

样例输入

复制样例数据

5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2

样例输出

2

因为如果要变动一条路使得主人公走远路的话,那么肯定是要变动他的最短路,由于图可能很复杂,变动最短路上的任意一条路都可能造成意想不到的效果,所以要把这条最短路上的每一条边都尝试改变一下,求得最大值。

而如果要回溯路径的话,就需要一个标记数组以及DFS,然后按照链式前向星的思路沿着原路(双向图允许这种操作)回去。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll lldcin()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
struct node
{
 mutable ll next,to,value;
}nodes[50000];
ll heads[50000],dis[50000],cnt=0;
bool vis[50000];
ll path2[50000],path[50000];
void cons(ll from,ll to,ll v)
{
    nodes[cnt]=node{heads[from],to,v};
    heads[from]=cnt++;
}
struct info
{
  ll current,status,cost;
};
bool operator<(info a,info b)
{
    return a.cost>b.cost;
}
void dij(ll s,ll h)//优先队列优化的迪杰斯特拉
{
   reset(vis,0);
   reset(dis,0x3f3f3f);
   priority_queue<info>pq;
   pq.push(info{s,0,0});
   dis[s]=0;
   while(!pq.empty())
   {
       info cur=pq.top();
       pq.pop();
       if(vis[cur.current])
         continue;
       vis[cur.current]=1;
       for(int i=heads[cur.current];i!=-1;i=nodes[i].next)
       {
          ll t=nodes[i].to;
          if(dis[t]>dis[cur.current]+nodes[i].value)
          {
            //cout<<nodes[i].value<<endl;
            dis[t]=dis[cur.current]+nodes[i].value;
            pq.push(info{t,0,cur.cost+nodes[i].value});
            path[t]=cur.current;
          }
          if(cur.status<h)
          {
            if(dis[t]>dis[cur.current]+2*nodes[i].value)
            {
               dis[t]=dis[cur.current]+2*nodes[i].value;
               pq.push(info{t,cur.status+1,cur.cost+2*nodes[i].value});
               path[t]=cur.current;
            }
          }
       }
   }
}
void show(ll e)//路径展示,校对用
{
  ll from=path[e];
  stack<ll>stk;
  stk.push(e);
  while(vis[from])
  {
    stk.push(from);
    from=path[from];
  }
  while(stk.size())
  {
    cout<<stk.top()<<endl;
    stk.pop();
  }
}
ll ans=0;
void traceback(ll current,ll n)//回溯路径
{
    for(int i=heads[current];i!=-1;i=nodes[i].next)
    {
        ll to=nodes[i].to;
        if(to==path2[current])
        {
            nodes[i].value*=2;//暂时变更权值
            dij(n,0);
            ans=max(ans,dis[1]);
            nodes[i].value/=2;
            traceback(to,n);
        }
    }
}
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    ll n,m;
    cin>>n>>m;
    reset(heads,-1);
    for(int i=1;i<=m;i++)
    {
        ll tmp1,tmp2,tmp3;
        cin>>tmp1>>tmp2>>tmp3;
        cons(tmp1,tmp2,tmp3);
        cons(tmp2,tmp1,tmp3);
    }
    dij(1,0);
    memcpy(path2,path,sizeof(path));
    ll fir=dis[n];
    //show(n);
    traceback(n,n);
    cout<<ans-fir<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值