本来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短路-可持久化可并堆的更多相关文章

  1. luogu 2483 K短路 (可持久化左偏树)

    题面: 题目大意:给你一张有向图,求1到n的第k短路 $K$短路模板题 假设整个图的边集为$G$ 首先建出以点$n$为根的,沿反向边跑的最短路树,设这些边构成了边集$T$ 那么每个点沿着树边走到点$n ...

  2. 图论(A*算法,K短路) :POJ 2449 Remmarguts' Date

    Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 25216   Accepted: 6882 ...

  3. 图论&搜索:K短路-启发式搜索

    判断第k短路的权值是否小于T 直接把队友的代码拿过来了,一定很经典 #include <iostream> #include <queue> #include <cstr ...

  4. 与图论的邂逅07:K短路

    在做最短路的题时我们不免会碰到许多求次短路的题,然而我们也能很快地想到解决的办法: 用dijkstra跑一遍最短路,当终点第二次被取出时就是次短路了.时间复杂度为O((N+M)logN).实际上前面得 ...

  5. 浅谈k短路算法

    An Old but Classic Problem 给定一个$n$个点,$m$条边的带正权有向图.给定$s$和$t$,询问$s$到$t$的所有权和为正路径中,第$k$短的长度. Notice 定义两 ...

  6. bzoj 1598: [Usaco2008 Mar]牛跑步 [k短路 A*] [学习笔记]

    1598: [Usaco2008 Mar]牛跑步 题意:k短路 ~~貌似A*的题目除了x数码就是k短路~~ \[ f(x) = g(x) + h(x) \] \(g(x)\)为到达当前状态实际代价,\ ...

  7. K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院

    A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数 这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离 通常和Dijkstra一起解决K短路 BZOJ1598 ...

  8. 算法笔记--次小生成树 && 次短路 && k 短路

    1.次小生成树 非严格次小生成树:边权和小于等于最小生成树的边权和 严格次小生成树:    边权和小于最小生成树的边权和 算法:先建好最小生成树,然后对于每条不在最小生成树上的边(u,v,w)如果我们 ...

  9. P2483 【模板】k短路([SDOI2010]魔法猪学院)

    题目背景 感谢@kczno1 @X_o_r 提供hack数据 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界 ...

随机推荐

  1. Git使用之二:下载远程代码到本地指定文件夹

    一.前期工作: 1.准备好本地的文件夹 2.如果后期需要继续以该文件夹进行同步的,则需要配置该文件夹,方法请参考之前的  Git使用之一:创建仓储和提交文件 二.用clone(克隆方式下载) 在本地下 ...

  2. 成都Uber优步司机奖励政策(3月25日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  3. find的详细使用

    对我我这个出学者,这个已经算是很难了,不过今天整理了一下,感觉还可以接受. find Linux中十分重要的一个查找功能, [root@moban /]# find /tmp/ -type f -na ...

  4. Python|花了一天,为大家整理的一套来自外国大佬的密码速查表

    简单的HTTPS服务器 检查证书信息 输出 生成自签名证书 输出 准备一个签名注册请求 输出 生成无密码的RSA秘钥文件 用一个私钥给文件签名 输出 从签名验证一个文件 输出 通过pem文件做RSA加 ...

  5. BFS实现模板

    以如下图的无向图G4为例,进行图的深度优先搜索: 假设从顶点v1出发进行搜索,首先访问v1和v1的邻接点v2和v3,然后依次访问v2的邻接点v4和v5及v3的邻接点v6和v7,最后访问v4的邻接点v8 ...

  6. lintcode-137-克隆图

    137-克隆图 克隆一张无向图,图中的每个节点包含一个 label 和一个列表 neighbors. 数据中如何表示一个无向图?http://www.lintcode.com/help/graph/ ...

  7. CodeForces Round #521 (Div.3) E. Thematic Contests

    http://codeforces.com/contest/1077/problem/E output standard output Polycarp has prepared nn competi ...

  8. 微信PC端授权页面提示授权入口所在域名为空

    做第三方微信平台的时候做授权页面,用window.open方法从第三方平台页面打开新的授权标签页. 在IE浏览器上出问题,提示如下: 在chrome和firefox浏览器上正常. 搜了一下,发现微信是 ...

  9. android开发中常犯的几个错误整理

    新手程序猿,在开发中难免会犯各种各样的错误,以下是整理的一些android开发中常见的错误,一起来看看吧. 1.避免将多个类放在一个文件夹里面,除非是一次性使用的内部类. 就是一个文件,最好给分它同名 ...

  10. Sublime Text 2.0.2 注册码激活

    直接输入注册码就可以了 ----- BEGIN LICENSE ----- Andrew Weber Single User License EA7E-855605 813A03DD 5E4AD9E6 ...