数据结构&图论: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对猪世界 ...
随机推荐
- FireDAC 连接Access (accdb)数据库
FireDAC可以方便连接数据库,但是要连接新版本的accdb数据库,要注意这样的事项(以Office2010版为例) 安装Office2010 x86版,注意,不能安装x64版,因为Delphi I ...
- java设计模式大全 Design pattern samples in Java(最经典最全的资料)
java设计模式大全 Design pattern samples in Java(最经典最全的资料) 2015年06月19日 13:10:58 阅读数:11100 Design pattern sa ...
- win10子系统Ubuntu18.04下安装图形界面
前提:windows 10 已经安装WSL(windows subsystem for linux),并能正确运行Bash. 要想使用Linux的图形用户界面通常有两种方法,一种是使用X-Window ...
- cartographer 安装修改
装置:VLP16+IMU+单板机 目的:利用传感器数据,实现real time 的建模 结果:失败,但之前的步骤都正常,出问题的地方可能是imu出错. 稍后附上 launch文件,lua文件,urdf ...
- Queue模块初识
Queue模块实现了多生产者.多消费者队列.它特别适用于信息必须在多个线程间安全地交换的多线程程序中.这个模块中的Queue类实现了所有必须的锁语义.它依赖于Python中线程支持的可用性:参见thr ...
- AMF3 在Unity中使用AMF3和Java服务器通信
现在在做的项目是一个网页游戏的移植到移动端. 所以服务器直接使用原来的代码.原来的游戏是as3实现,使用flash amf3数据通信. Unity 使用C#作为脚本语言,所以就需要.net的amf3解 ...
- EasyUI 布局 - 动态添加标签页(Tabs)
首先导入js <link rel="stylesheet" href="../js/easyui/themes/default/easyui.css"&g ...
- SourceTree git的管理工具使用教程1
1SourceTree是一个window系统下的Git管理工具 2设置Git 工具——选项——Git设置 3拷贝远程的项目 新建/克隆(输入远程项目的url地址) 4验证(填写用户信息) 工具——选项 ...
- Spring Boot(一)入门篇
SpringBoot概述 Spring Boot的诞生简化了Spring应用开发,SpringBoot提供对Spring容器.第三方插件等很多服务的管理.对于大部分Spring应用,无论是简单的web ...
- nginx开机自启动
配置步骤:1 . vi /etc/init.d/nginx2. chkconfig --level nginx 2345 on --重点 --------------------以下为nginx配置文 ...