数据结构&图论:K短路-可持久化可并堆
本来A*就可以搞定的题,为了怕以后卡复杂度,找了个这么个方法
现阶段水平不够就不补充算法分析部分了
- 对于图G,建立一个以终点t为起点的最短路径构成的最短路径树
- (就是反着跑一遍最短路,然后对于一个不为终点的点v,v到终点t的最短路径上(任选一条)v的后继结点为v的父亲,就形成了一棵树)
- 然后对于所有点,定义其不在最短路径树上的出边的f值为:f[e] = l[e] + dis[e.tail] - dis[e.head] ,就是走这条边,走到t需要多绕的距离
- 那么我们只要找到第k小的这种边的序列就得到解了
- 那么我们维护按权值一个从小到大的优先队列,每次从队头取出一个序列q,设q的最后一条边e的head为u,tail为v
- 我们可以选择在序列的末尾加上v到t的所有路径上非树边的最小的得到一个新的序列q1
- 或者选择u到t的所有路径上所有非树边中e的后继(没用过的边中最小的)替换e得到q2,将q1,q2都塞进优先队列,重复k次,
- 可是怎么才能尽快知道一个节点v到t的所有路径上的非树边最小的一个呢?
- 打个可持久化的可并堆就没问题了,每个点合并他到根的路径上所有非树出边,然后对于找e的后继替换e的操作,直接找e的两个孩子就行了
本题难度爆表,低级图论和高级数据结构的大综合
直接上代码了,以后学的多了再回过头来看方法
- #include<cstdio>
- #include<algorithm>
- #include<cstring>
- #include<queue>
- using namespace std;
- const int maxn=; //为啥开这么大???
- const int maxm=;
- const int INF=0x7fffffff;
- int n,m,cnt,cntf,st,ed,k,tot,tp;
- bool vi[maxn];
- int g[maxn],gf[maxn],dis[maxn],_next[maxn],root[maxn],sta[maxn];
- struct Edge
- {
- int u,v,w,f,next;
- bool vis,flag;
- }e[maxm];
- struct Edgef
- {
- int t,w,next;
- }ef[maxm];
- void addedge(int x,int y,int z)
- {
- cnt++;
- e[cnt].u=x;e[cnt].v=y;e[cnt].w=z;
- e[cnt].next=g[x];g[x]=cnt;
- e[cnt].vis=;
- }
- void addedgef(int x,int y,int z)
- {
- cntf++;
- ef[cntf].t=y;ef[cntf].w=z;
- ef[cntf].next=gf[x];gf[x]=cntf;
- }
- struct Node
- {
- int lc,rc,dis,c,y;
- }tr[maxn*];
- int newnode(int c,int y)
- {
- tot++;
- tr[tot].lc=tr[tot].rc=;
- tr[tot].dis=;
- tr[tot].c=c;
- tr[tot].y=y;
- return tot;
- }
- int merge(int x,int y)
- {
- //cout<<x<<" "<<y<<endl;
- if(x==||y==) return x|y;
- if(tr[x].c>tr[y].c) swap(x,y);
- int ret=++tot;
- tr[ret]=tr[x];
- int k=merge(tr[ret].rc,y);
- if(tr[tr[ret].lc].dis<=tr[k].dis) swap(tr[ret].lc,k);
- tr[ret].rc=k;
- tr[ret].dis=tr[tr[ret].lc].dis+;
- return ret;
- }
- struct HeapNode
- {
- int x,d;
- };
- bool operator <(HeapNode x,HeapNode y)
- {
- return x.d>y.d;
- }
- priority_queue<HeapNode> q;
- struct Graph
- {
- int u,x,d;
- };
- bool operator < (Graph x,Graph y)
- {
- return x.d>y.d;
- };
- priority_queue<Graph> Q;
- void getdis()
- {
- dis[ed]=;
- HeapNode temp;
- temp.x=ed;temp.d=;
- q.push(temp);
- while(!q.empty())
- {
- HeapNode x=q.top();q.pop();
- if(dis[x.x]<x.d) continue;
- for(int tmp=gf[x.x];tmp;tmp=ef[tmp].next)
- {
- int y=ef[tmp].t;vi[y]=;
- if(dis[y]>x.d+ef[tmp].w)
- {
- dis[y]=x.d+ef[tmp].w;
- temp.x=y;temp.d=dis[y];
- q.push(temp);
- }
- }
- }
- }
- void solve(int x)
- {
- if(x==ed)
- {
- for(int tmp=g[x];tmp;tmp=e[tmp].next)
- {
- int y=e[tmp].v;
- if(e[tmp].flag==) continue;
- if(e[tmp].vis==)
- {
- root[x]=merge(root[x],newnode(e[tmp].f,e[tmp].v));
- }
- }
- return;
- }
- for(int tmp=g[x];tmp;tmp=e[tmp].next)
- {
- int y=e[tmp].v;
- if(e[tmp].flag==) continue;
- if(e[tmp].vis==)
- root[x]=merge(root[x],newnode(e[tmp].f,e[tmp].v));
- else root[x]=merge(root[x],root[y]);
- }
- }
- int main()
- {
- int u,v,w;
- scanf("%d%d",&n,&m);
- for(int i=;i<=m;i++)
- {
- scanf("%d%d%d",&u,&v,&w);
- addedge(u,v,w);
- e[cnt].flag=;
- addedgef(v,u,w);
- }
- scanf("%d%d%d",&st,&ed,&k);
- if(st==ed) k++;
- for(int i=;i<=n;i++)
- dis[i]=INF,vi[i]=;
- getdis();
- if(k==)
- {
- if(vi[st]) printf("%d\n",dis[st]);
- else printf("-1\n");
- return ;
- }
- for(int i=;i<=cnt;i++)
- {
- e[i].f=e[i].w-dis[e[i].u]+dis[e[i].v];
- if(dis[e[i].v]==INF) e[i].flag=;
- }
- for(int i=;i<=n;i++)
- {
- if(i==ed) continue;
- for(int tmp=g[i];tmp;tmp=e[tmp].next)
- {
- v=e[tmp].v;
- if(!e[tmp].flag) continue;
- if(dis[i]==dis[v]+e[tmp].w)
- {
- e[tmp].vis=;
- _next[i]=v;
- break;
- }
- }
- }
- memset(root,,sizeof(root));
- tot=;
- for(int i=;i<=n;i++)
- if(!root[i])
- {
- if(dis[i]==INF) continue;
- sta[tp=]=i;
- while()
- {
- u=sta[tp];
- if(u==ed) break;
- if(!root[_next[u]]) sta[++tp]=_next[u];
- else break;
- }
- while(tp)
- {
- solve(sta[tp]);
- tp--;
- }
- }
- k-=;
- Graph ss;
- ss.u=st;ss.d=tr[root[st]].c;ss.x=root[st];
- Q.push(ss);
- while(k--)
- {
- Graph tmp=Q.top();Q.pop();
- if(tmp.u==)
- {
- printf("-1\n");
- return ;
- }
- if(tr[tmp.x].lc)
- {
- Graph tmp1;
- tmp1.u=tmp.u;
- tmp1.d=-tr[tmp.x].c;
- tmp1.x=merge(tr[tmp.x].lc,tr[tmp.x].rc);
- tmp1.d+=tr[tmp1.x].c+tmp.d;
- Q.push(tmp1);
- }
- Graph tmp2;
- tmp2.u=tr[tmp.x].y;
- tmp2.d=tmp.d+tr[root[tmp2.u]].c;
- tmp2.x=root[tmp2.u];
- Q.push(tmp2);
- }
- Graph ans=Q.top();
- if(ans.u==)
- {
- printf("-1\n");
- return ;
- }
- if(vi[st]) printf("%d\n",dis[st]+ans.d);
- else printf("-1\n");
- return ;
- }
200多行幸亏没出什么调不出来的错误,唉,菜啊
数据结构&图论:K短路-可持久化可并堆的更多相关文章
- luogu 2483 K短路 (可持久化左偏树)
题面: 题目大意:给你一张有向图,求1到n的第k短路 $K$短路模板题 假设整个图的边集为$G$ 首先建出以点$n$为根的,沿反向边跑的最短路树,设这些边构成了边集$T$ 那么每个点沿着树边走到点$n ...
- 图论(A*算法,K短路) :POJ 2449 Remmarguts' Date
Remmarguts' Date Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 25216 Accepted: 6882 ...
- 图论&搜索:K短路-启发式搜索
判断第k短路的权值是否小于T 直接把队友的代码拿过来了,一定很经典 #include <iostream> #include <queue> #include <cstr ...
- 与图论的邂逅07:K短路
在做最短路的题时我们不免会碰到许多求次短路的题,然而我们也能很快地想到解决的办法: 用dijkstra跑一遍最短路,当终点第二次被取出时就是次短路了.时间复杂度为O((N+M)logN).实际上前面得 ...
- 浅谈k短路算法
An Old but Classic Problem 给定一个$n$个点,$m$条边的带正权有向图.给定$s$和$t$,询问$s$到$t$的所有权和为正路径中,第$k$短的长度. Notice 定义两 ...
- bzoj 1598: [Usaco2008 Mar]牛跑步 [k短路 A*] [学习笔记]
1598: [Usaco2008 Mar]牛跑步 题意:k短路 ~~貌似A*的题目除了x数码就是k短路~~ \[ f(x) = g(x) + h(x) \] \(g(x)\)为到达当前状态实际代价,\ ...
- K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院
A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数 这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离 通常和Dijkstra一起解决K短路 BZOJ1598 ...
- 算法笔记--次小生成树 && 次短路 && k 短路
1.次小生成树 非严格次小生成树:边权和小于等于最小生成树的边权和 严格次小生成树: 边权和小于最小生成树的边权和 算法:先建好最小生成树,然后对于每条不在最小生成树上的边(u,v,w)如果我们 ...
- P2483 【模板】k短路([SDOI2010]魔法猪学院)
题目背景 感谢@kczno1 @X_o_r 提供hack数据 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界 ...
随机推荐
- Delphi中Templates代码模板添加注意事项
今天用Delphi中的代码模板添加一段代码,结果就是有问题,多次测试后,发现是编码需要注意. <?xml version="1.0" encoding="GB231 ...
- CSS3实现加载数据动画2
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Ganglia3.1.7安装与配置(收录)
一.所需要软件 二.安装过程 1.Ganglia运行平台的安装 2.Ganglia依赖库的安装 3.RRDTool的安装 4.Ganglia的安装 (包括使用yum方式 ...
- cmd中可以运行java,但不能运行javac命令
在cmd中可以运行java,但运行javac命令时提示:'javac' 不是内部或外部命令,也不是可运行的程序或批处理文件. 原因:安装java时把jdk的路径和jre的路径选择成一样,就造成覆盖了. ...
- shell -- shift用法
shift是Unix中非常有用的命令.可以使命令参数左移,从而使脚本程序中命令参数位置不变的情况下依次遍历所有参数.如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1. ...
- Linux - 信息收集
1. #!,代表加载器(解释器)的路径,如: #!/bin/bash echo "Hello Boy!" 上面的意思是说,把下面的字符(#!/bin/bash以下的所有字符)统统传 ...
- XenServer设置master,摧毁故障主机
XenServer pool 移除server 设置master 这分为Pool Master是正常还是异常2种情况: 正常情况下可能要对Pool Master做一些停机维护,比如换内存条啥的,此时在 ...
- 第十九章 Python os模块,pathlib 判断文件是目录还是文件
OS模块 os.path.abspath() :返回path规范化的绝对路径 import sys import os BASE_DIR = os.path.dirname(os.path.dirna ...
- postgres(pl/pgsql)
复制后期看 https://www.cnblogs.com/stephen-liu74/archive/2012/06/06/2312759.html https://www.cnblogs.com/ ...
- Javascript Array和String的互转换
Array类可以如下定义: var aValues = new Array(); 如果预先知道数组的长度,可以用参数传递长度 var aValues = new Array(20); -------- ...