洛谷p2176[最短路]

https://www.luogu.org/problemnew/show/P2176
题意:n个点,m条路,如果使某条道路长度翻倍,求此时最短路与未改变前的最短路的差的最大值。

思路:先求一边最短路,并记录路径。然后回溯路径,改变这条最短路的路径上的道路长度,计算并比较出最大的差值。
之所以只改变最短路上的值,是因为哪怕改变了别的道路的长度,最短路的值不会改变,是无效的改变。

代码待优化

#include <stdio.h>
#include <queue>
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <deque>
#include <vector>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn=10010;

priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
//priority_queue<Type, Container, Functional>  **优先队列**
//其中Type 为数据类型,Container为保存数据的容器,Functional 为元素比较方式
struct node
{
    int to,val;
} add;
vector<node>G[110];
void addedge(int u,int v,int w)
{
    add.to=v;
    add.val=w;
    G[u].push_back(add);
}
struct Node
{
    int from,to,val;
} d[110];
int vis[110];
int n,m,h,ans,c_1,c_2,dis[110],pre[110],last;
void pri(int i)
{
    if(d[i].from==0)
        return;
    pri(d[i].from);
    pre[++h]=i;
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1; i<=m; i++)
    {
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        addedge(a,b,c);
        addedge(b,a,c);
    }
    memset(d,INF,sizeof(d));
    d[1].from=0;
    d[1].val=0;
    q.push(make_pair(0,1));
    while(!q.empty())
    {
        int now=q.top().second;
        q.pop();
        if(vis[now])
            continue;
        vis[now]=1;
        for(int i=0; i<G[now].size(); i++)
        {
            int to=G[now][i].to;
            if(d[to].val>d[now].val+G[now][i].val)
            {
                d[to].val=d[now].val+G[now][i].val;
                d[to].from=now;
                q.push(make_pair(d[to].val,to));
            }
        }
    }
    pri(n);
    last=1;
    for(int i=1; i<=h; i++)
    {
        for(int j=0; j<G[last].size(); j++)
        {
            if(G[last][j].to==pre[i])
            {
                G[last][j].val<<=1;
                c_1=j;
                break;
            }
        }
        for(int j=0; j<G[pre[i]].size(); j++)
        {
            if(G[pre[i]][j].to==last)
            {
                G[pre[i]][j].val<<=1;
                c_2=j;
                break;
            }
        }
        memset(dis,INF,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[1]=0;
        q.push(make_pair(0,1));
        while(!q.empty())
        {
            int now=q.top().second;
            q.pop();
            if(vis[now])
                continue;
            vis[now]=1;
            for(int j=0;j<G[now].size();j++)
            {
                  if(dis[G[now][j].to]>dis[now]+G[now][j].val)
                  {
                        dis[G[now][j].to]=dis[now]+G[now][j].val;
                        q.push(make_pair(dis[G[now][j].to],G[now][j].to));
                  }
            }
        }
        if(dis[n]-d[n].val>ans)
        {
              ans=dis[n]-d[n].val;
        }
        G[last][c_1].val>>=1;
        G[pre[i]][c_2].val>>=1;
        last=pre[i];
    }
    printf("%d\n",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值