HDU 5168 Legal path 最短路 OR DP

43 篇文章 0 订阅
HDU 5168
题意:n个结点的有向图,边带权.定义合法路径为:该路径上的每条边都满足比它前一条至少大k.
合法路径的长度为:该路径上所有边的权值.可能有重边.
n,m<=2e5,k,c[i]<=1e9.问从1->n的最短合法路径.

记录前面一个边的值 然后直接跑SPFA WA.... 
1
6 7 2
1 2 2
2 3 4
3 4 6
1 5 3
5 4 8
4 6 8
4 6 10
u-v边较小,后面机会可能多,则需要压入队列,但是因为dis[u]+w1>dis[v] 这种情况被忽视了. 
注意在压入队列的同时不能更新二元组(dis[v],w1) 因为这两个可能是不同的路径.要更新(dis[u]+w1,w1).
最短路也是可以做的 注意细节 点击打开链接


官方解是DP.
先将所有的边从小到大排序,每次更新(u,v,w)边中的v. 则要知道到当前1-u的"最优"值(1-u路径中边权值+k<=w,否则即使dis[u]此时是最优的,也不能直接走u-v边).

则用se[u]来维护:路径中边权值+k<=w时的,1-u的最短路.即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const ll inf=2e16;
struct node{
    int u,v;
    ll w,dis;
}e[N];//e[i].dis -> 1->v 's dis (go through u);
int u,v;
ll n,m,k,w,dis[N];
set<ll> se[N];
bool cmp(node a,node b){return a.w<b.w;}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++)
            se[i].clear(),dis[i]=inf;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lld",&u,&v,&w);
            e[i].u=u,e[i].v=v,e[i].w=w;
            if(u==1)
                e[i].dis=w,dis[v]=min(dis[v],w);
            else
                e[i].dis=inf;
        }
        sort(e+1,e+1+m,cmp);
        int j=1;
        for(int i=1;i<=m;i++)
        {
            while(j<i&& e[j].w+k<=e[i].w )
            {
                se[e[j].v].insert(e[j].dis);
                j++;
            }
            if(!se[e[i].u].empty())
                e[i].dis=min(e[i].dis,*se[e[i].u].begin()+e[i].w);
            dis[e[i].v]=min(dis[e[i].v],e[i].dis);
        }
        if(dis[n]==inf)
            dis[n]=-1;
        cout<<dis[n]<<endl;
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值