题解

(搬运一个原来博客的论文题)

抱着板题的心情去,结果有大坑

就是S == T的时候也一定要走,++K

我发现按照论文写得\(O(n \log n + m + k \ log k)\)算法没有玄学A*快,不开心啊(或者我松教水平不高啊)

论文里主要是怎么样呢,把所有边反向,从T开始求最短路,然后求一个最短路树,求法就是把新边权改成

原来的边权 + 终点最短路 - 起点最短路

如果新边权是0,那么这条边就在最短路树里,如果有很多条边边权是0就随便选一条

然后我们对于每个点走一条不同于最短路的路径,发现是走过的非树边的边权加上S到T的最短路

我们记录每个点拓展出去的边都有哪些,拓展出去的边从小到大排序,一个点同时可以拓展它父亲可以拓展的边

这样我们可以用一个可持久化左偏树来维护,按照左儿子右兄弟的方法扩展,删掉一个点然后把左右儿子合起来选次大,或者再从当前点走一条非树边

不过删掉一个点把左右儿子加进去也可以

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <cmath>
#define MAXN 5005
#define PII pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64; int N,M,St,T,K,dis[MAXN];
vector<PII > G[MAXN],G_rev[MAXN];
vector<int> son[MAXN];
int fa[MAXN];
bool vis[MAXN],ct[MAXN];
PII line[200005];
struct cmp1 {
bool operator ()(const PII &a, const PII &b) {
return a.se > b.se;
}
}; struct Left_Tree {
Left_Tree *lc,*rc;
int v,to,dis;
}pool[8000005],*tail = pool;
vector<Left_Tree*> rt[MAXN];
struct node {
int s,t,cnt,v1,v0;
friend bool operator < (const node &a,const node &b) {
if(a.v1 != b.v1) return a.v1 < b.v1;
else if(a.v0 != b.v0) return a.v0 < b.v0;
else if(a.s != a.s) return a.s < b.s;
else return a.t < b.t;
}
};
multiset<node> S;
priority_queue<PII,vector<PII >,cmp1> Q;
Left_Tree *Newnode(PII k) {
Left_Tree *res = tail++;
res->v = k.se;res->to = k.fi;
res->lc = res->rc = NULL;
res->dis = 0;
return res;
}
int get_dist(Left_Tree *r) {
if(!r) return -1;
else return r->dis;
}
Left_Tree* Merge(Left_Tree *A,Left_Tree *B) {
if(!A) return B;
if(!B) return A;
if(A->v > B->v) swap(A,B);
Left_Tree *res = tail++;
*res = *A;
res->rc = Merge(A->rc,B);
if(get_dist(res->lc) < get_dist(res->rc)) swap(res->lc,res->rc);
res->dis = get_dist(res->rc) + 1;
return res;
}
Left_Tree* build(int u,int tot) {
if(u > tot) return NULL;
Left_Tree *res = Newnode(line[u]);
res->lc = build(u << 1,tot);
res->rc = build(u << 1 | 1,tot);
if(get_dist(res->lc) < get_dist(res->rc)) swap(res->lc,res->rc);
res->dis = get_dist(res->lc) + 1;
return res;
}
void dfs(int u) {
int tot = 0;
for(int i = 0 ; i < G[u].size() ; ++i) {
PII k = G[u][i];
if(ct[k.fi]) continue;
if(k.se != 0 || vis[u]) {
line[++tot] = k;
int t = tot;
while(t != 1) {
if(line[t].se < line[t >> 1].se) {
swap(line[t],line[t >> 1]);
t >>= 1;
}
else break;
}
}
else vis[u] = 1;
}
rt[u].pb(build(1,tot));
if(fa[u]) rt[u][0] = Merge(rt[u][0],rt[fa[u]][0]);
for(int i = 0 ; i < son[u].size() ; ++i) dfs(son[u][i]);
}
void Dijkstra() {
for(int i = 1 ; i <= N ; ++i) dis[i] = 0X7fffffff;
dis[T] = 0;
Q.push(mp(T,0));
while(!Q.empty()) {
PII u = Q.top();Q.pop();
if(vis[u.fi]) continue;
vis[u.fi] = 1;
for(int i = 0 ; i < G_rev[u.fi].size() ; ++i) {
PII k = G_rev[u.fi][i];
if(!vis[k.fi] && u.se + k.se < dis[k.fi]) {
dis[k.fi] = u.se + k.se;
Q.push(mp(k.fi,dis[k.fi]));
}
}
}
}
void Init() {
scanf("%d%d",&N,&M);
int s,t,c;
for(int i = 1 ; i <= M ; ++i) {
scanf("%d%d%d",&s,&t,&c);
G[s].pb(mp(t,c));
G_rev[t].pb(mp(s,c));
}
scanf("%d%d%d",&St,&T,&K);
Dijkstra();
for(int i = 1 ; i <= N ; ++i) {
if(dis[i] == 0x7fffffff) {ct[i] = 1;continue;}
for(int j = 0 ; j < G[i].size() ; ++j) {
G[i][j].se += dis[G[i][j].fi] - dis[i];
if(G[i][j].se == 0 && !fa[i]) {
fa[i] = G[i][j].fi;
son[fa[i]].pb(i);
}
}
}
memset(vis,0,sizeof(vis));
dfs(T);
}
void Solve() {
Init();
if(dis[St] == 0x7fffffff) {puts("-1");return;}
if(St == T) ++K;
if(K == 1) {printf("%d\n",dis[St]);return;}
if(rt[St][0]) {
S.insert((node){St,rt[St][0]->to,0,rt[St][0]->v,0});
}
int C = K - 2;
while(C && !S.empty()) {
C--;
node Now = *S.begin();
S.erase(S.begin());
while(rt[Now.s].size() <= Now.cnt + 1) {
int s = rt[Now.s].size() - 1;
rt[Now.s].pb(Merge(rt[Now.s][s]->lc,rt[Now.s][s]->rc));
}
if(rt[Now.s][Now.cnt + 1]) {
S.insert((node){Now.s,rt[Now.s][Now.cnt + 1]->to,Now.cnt + 1,Now.v0 + rt[Now.s][Now.cnt + 1]->v,Now.v0});
}
if(rt[Now.t][0]){
S.insert((node){Now.t,rt[Now.t][0]->to,0,Now.v1 + rt[Now.t][0]->v,Now.v1});
}
}
if(C || S.empty()) {
puts("-1");
}
else {
node Now = *S.begin();
printf("%d\n",Now.v1 + dis[St]);
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}

【POJ】2449.Remmarguts' Date(K短路 n log n + k log k + m算法,非A*,论文算法)的更多相关文章

  1. poj 2449 Remmarguts' Date(第K短路问题 Dijkstra+A*)

    http://poj.org/problem?id=2449 Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Subm ...

  2. POJ 2449 - Remmarguts' Date - [第k短路模板题][优先队列BFS]

    题目链接:http://poj.org/problem?id=2449 Time Limit: 4000MS Memory Limit: 65536K Description "Good m ...

  3. poj 2449 Remmarguts' Date (k短路模板)

    Remmarguts' Date http://poj.org/problem?id=2449 Time Limit: 4000MS   Memory Limit: 65536K Total Subm ...

  4. poj 2449 Remmarguts' Date K短路+A*

    题目链接:http://poj.org/problem?id=2449 "Good man never makes girls wait or breaks an appointment!& ...

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

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

  6. poj 2449 Remmarguts' Date 第k短路 (最短路变形)

    Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 33606   Accepted: 9116 ...

  7. poj 2449 Remmarguts' Date(K短路,A*算法)

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u013081425/article/details/26729375 http://poj.org/ ...

  8. K短路模板POJ 2449 Remmarguts' Date

      Time Limit: 4000MS   Memory Limit: 65536K Total Submissions:32863   Accepted: 8953 Description &qu ...

  9. POJ 2449 Remmarguts' Date (K短路 A*算法)

    题目链接 Description "Good man never makes girls wait or breaks an appointment!" said the mand ...

  10. POJ 2449 Remmarguts' Date(第k短路のA*算法)

    Description "Good man never makes girls wait or breaks an appointment!" said the mandarin ...

随机推荐

  1. 什么是ground truth(GT)

    转自ground truth的含义 ground truth在不同的地方有不同的含义,下面是参考维基百科的解释,ground truth in wikipedia. 1.在统计学和机器学习中 在机器学 ...

  2. Elasticsearch相关概念了解

    mysql ⇒数据库databases       ⇒表tables     ⇒ 行rows        ⇒ 列columns es   ⇒索引indices        ⇒ 类型types    ...

  3. 《Two Dozen Short Lessons in Haskell》(二十二)递归

    <Two Dozen Short Lessons in Haskell>(Copyright © 1995, 1996, 1997 by Rex Page,有人翻译为Haskell二十四学 ...

  4. ConcurrentHashMap 产生NullPointerException

    今天测试在发给我一段报错日志后,根据日志定位到从ConcurrentHashMap 的缓存中get的时候,ConcurrentHashMap的底层抛出了空指针,当时感觉很奇怪为什么在get的时候产生空 ...

  5. 【JAVA】配置JAVA环境变量,安装Eclipse

    Java程序依赖JDK,就像C#程序依赖.NetFrameWork一样. 所以在开发之前,必须在win7或者是linux上,安装jdk(JavaDevelopkit)里面包括java一些工具,还有JR ...

  6. 2016-2017-2 《Java程序设计》第六周学习总结

    20155223 2016-2017-2 <Java程序设计>第六周学习总结 教材学习内容总结 第十章 InputStream.OutputStream:无论数据源或目的地为何,只要设法取 ...

  7. HDU 1251 统计难题 (裸的字典树)

    题目链接 Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本 ...

  8. log4net记录系统错误日志到文本文件用法详解(最新)

    此配置文件可以直接拿来用,配置文件上面有详细用法说明,里面也有详细注释说明.此配置文件涵盖按照日期记录和按照文件大小(建议)的实例. 又包括:按照Fatal.Info.Error.Debug.Warn ...

  9. rsync同步文件(多台机器同步代码...)

    常用组合   rsync -av --delete-after --exclude-from="a.txt"  x/x -e ssh x:/x/x   a.txt 制定忽略的文件, ...

  10. 信息安全学习笔记--CSRF

      一.CSRF简介   CSRF(Cross-site request forgery)跨站请求伪造,也被称为“one click attack”或者“session riding”,通常缩写为CS ...