P4568 [JLOI2011]飞行路线

本文探讨了在特定问题场景下使用动态规划(DP)算法结合堆优化的实现细节,通过手写堆的方式进行深入解析,并提供了一种解决路径长度受限问题的有效方案。文章详细介绍了如何构建和维护堆结构,以及在DP算法中如何高效地更新和查找节点,避免了在某些情况下可能出现的heap_num≤0的问题。

用高度来限制 \(K\),这个很好理解,看第一位的图可知了。

当然 \(DP\) 也是可以的。

手写堆 \(7.in\) 会炸掉! 因为会有 \(heap_{num} \leq 0\) 的时候!

5bf95120d3c3a.png

// luogu-judger-enable-o2
// T1

Uses math;

var
    next,rope,from,value,reach:array[-1..21000000] of longint;
    heap,node:array[-1..21000000] of longint;
    dis,cnt:array[-1..510000] of longint;
    id:array[-1..510000,-1..11] of longint;
    ask:array[-1..510000] of boolean;
    l,r,k,i,j,n,m,num,tot,free,sink,source:longint;

procedure swap(var a,b:longint);var t:longint; begin t:=a; a:=b; b:=t; end;

procedure add(l,r,sum:longint);
begin
    inc(tot); from[tot]:=l; reach[tot]:=r; value[tot]:=sum; next[tot]:=cnt[l]; cnt[l]:=tot;
end;

procedure Insert(x:longint);
var father:longint;
begin
    if x=1 then exit;
    father:=x >> 1;
    if heap[father]>heap[x] then
    begin
        swap(heap[x],heap[father]); swap(node[x],node[father]);
        Insert(father);
    end;
end;

procedure Down(x:longint);
var son:longint;
begin
    if x << 1>num then exit;
    son:=x << 1;
    if (son+1<=num)and(heap[son+1]<=heap[son]) then inc(son);
    if heap[x]>heap[son] then begin swap(heap[x],heap[son]); swap(node[x],node[son]); end;
    Down(son);
end;

procedure Dijkstar;
var i,key,rope:longint;
begin
    fillchar(ask,sizeof(ask),0);
    rope:=0; dis[source]:=0; num:=0;
    for i:=1 to free do
    begin
        inc(num); heap[num]:=dis[id[source,i]]; node[num]:=id[source,i];
        Insert(num);
    end;
    repeat
        key:=node[1];
        heap[1]:=heap[num]; node[1]:=node[num];
        dec(num); down(1);
        if ask[key]=False then
        begin
            inc(rope); ask[key]:=True;
            i:=cnt[key];
            while i<>-1 do
            begin
                if (dis[reach[i]]>value[i]+dis[key]) then
                begin
                    dis[reach[i]]:=value[i]+dis[key];
                    inc(num); heap[num]:=dis[reach[i]]; node[num]:=reach[i];
                    Insert(num);
                end;
                i:=next[i];
            end;
        end;
    until rope=n*free;
end;

begin
    filldword(dis,sizeof(dis) div 4,maxlongint div 84);
    filldword(cnt,sizeof(cnt) div 4,maxlongint*2+1);
    filldword(heap,sizeof(heap) div 4,0);
    read(n,m,free,source,sink);
    inc(free); inc(source); inc(sink);
    for j:=1 to free do for i:=1 to n do id[i,j]:=(j-1)*n+i;
    for j:=1 to free do dis[id[source,j]]:=0;
    for i:=1 to m do
    begin
        read(l,r,k); inc(l); inc(r);
        for j:=1 to free do begin add(id[l,j],id[r,j],k); add(id[r,j],id[l,j],k); end;
        for j:=1 to free-1 do begin add(id[l,j],id[r,j+1],0); add(id[r,j],id[l,j+1],0); end;
    end;
    Dijkstar;
    writeln(dis[id[sink,free]]);
end.

转载于:https://www.cnblogs.com/FibonacciHeap/articles/10321812.html

#include<bits/stdc++.h> using namespace std; const int N=1e4+5; struct node { int to,w; vector<int> way; bool operator <(const node& a)const { return w>a.w; } } e,p; priority_queue<node> q; vector<node> g[N]; vector<int> val(N,INT_MAX); int n,m,k,s,t,u,v,w; bool fl[N]; void dij() {//获取最优路径,从最优路径上减去最大权值边 e.to=s; q.push(e); val[s]=0; while(!q.empty()) { e=q.top(); q.pop(); if(e.to==t) { sort(e.way.begin(),e.way.end()); while(!e.way.empty()&&k) { e.w-=e.way.back(); e.way.pop_back(); k--; } cout<<e.w; return; } if(fl[e.to])continue; fl[e.to]=true; for(node &x:g[e.to]) { if(e.w+x.w<val[x.to]) { p=e; p.to=x.to; p.w+=x.w; p.way.emplace_back(x.w); val[x.to]=e.w+x.w; q.push(p); } } } } int main() { ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin>>n>>m>>k>>s>>t; while(m--) { cin>>u>>v>>w; g[u].push_back({v,w}); g[v].push_back({u,w}); } dij(); return 0; }# P4568 [JLOI2011] 飞行路线 ## 题目描述 Alice 和 Bob 现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在 $n$ 个城市设有业务,设这些城市分别标记为 $0$ 到 $n-1$,一共有 $m$ 种航线,每种航线连接两个城市,并且航线有一定的价格。 Alice 和 Bob 现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多 $k$ 种航线上搭乘飞机。那么 Alice 和 Bob 这次出行最少花费多少? ## 输入格式 第一行三个整数 $n,m,k$,分别表示城市数,航线数和免费乘坐次数。 接下来一行两个整数 $s,t$,分别表示他们出行的起点城市编号和终点城市编号。 接下来 $m$ 行,每行三个整数 $a,b,c$,表示存在一种航线,能从城市 $a$ 到达城市 $b$,或从城市 $b$ 到达城市 $a$,价格为 $c$。 ## 输出格式 输出一行一个整数,为最少花费。 ## 输入输出样例 #1 ### 输入 #1 ``` 5 6 1 0 4 0 1 5 1 2 5 2 3 5 3 4 5 2 3 3 0 2 100 ``` ### 输出 #1 ``` 8 ``` ## 说明/提示 #### 数据规模与约定 对于 $30\%$ 的数据,$2 \le n \le 50$,$1 \le m \le 300$,$k=0$。 对于 $50\%$ 的数据,$2 \le n \le 600$,$1 \le m \le 6\times10^3$,$0 \le k \le 1$。 对于 $100\%$ 的数据,$2 \le n \le 10^4$,$1 \le m \le 5\times 10^4$,$0 \le k \le 10$,$0\le s,t,a,b < n$,$a\ne b$,$0\le c\le 10^3$。 另外存在一组 hack 数据。 这道题里我通过记录最大权值边来减去,以此得到结果,但问题是减去back的代码没有执行,样例结果得到13,我需要你分析原因
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值