本来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. C++11中std::function的使用

    class template std::function is a general-purpose polymorphic function wrapper. Instances of std::fu ...

  2. Django 2.0官方文档中文 渣翻 总索引(个人学习,欢迎指正)

    Django 2.0官方文档中文 渣翻 总索引(个人学习,欢迎指正) 置顶 2017年12月08日 11:19:11 阅读数:20277 官方原文: https://docs.djangoprojec ...

  3. jmeter添加自定义扩展函数之图片base64编码

    打开eclipse,新建maven工程,在pom中引入jmeter核心jar包: <!-- https://mvnrepository.com/artifact/org.apache.jmete ...

  4. Mysql性能优化一:SQL语句性能优化

    这里总结了52条对sql的查询优化,下面详细来看看,希望能帮助到你 1, 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2,应尽量避免在 w ...

  5. Cross Entropy in Machine Learning

    整理摘自:https://blog.csdn.net/tsyccnh/article/details/79163834 信息论 Outline 1. 信息量与信息熵 2. 相对熵(KL散度) 3. 交 ...

  6. POJ 2186 Popular Cows(强联通+缩点)

    Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= ...

  7. NO4——并查集

    int find(int x) { int r = x; while(father[r]!=r) r = father[r]; return r; } /* int find(int x) { if( ...

  8. NO1——线段树

    /* 数组存储 */ /* 预处理 */ #include <iostream> #include <cstdio> #include <algorithm> #i ...

  9. 深夜浅谈我理解的DIV对SEO的影响

    又到了夜深人静的时候,对于以前的我来说每天的这个时候都是在敲一下代码啊或者看一会书,但是今夜突然间又一次心血来潮,想写一篇博文来记录一下这一段时间做SEO优化所遇到的问题. 其实对于我来说SEO并不是 ...

  10. hdu 1856 More is better (并查集)

    More is better Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 327680/102400 K (Java/Others) ...