[JZOJ5279]香港记者题解--最短路图

[JZOJ5279]香港记者题解--最短路图

题目链接

过 于 暴 力

分析

有一个naiive的想法就是从1到n跑最短路,中途建图,然后在图上按字典序最小走一遍,然而·这是不行的,你这样跳不一定能跳到终点.

所以应该是在1到n的最短路图上跳,怎么求有向图短路图?你跑一遍1到n得到\(dist1[]\),n到1的最短路得到\(dist[2]\),然后从1 BFS,对于原图一条\(u\),连向\(v\)的边,若\(dis1[u]+dis2[v]+dis(u,v)\)等于1到n的最短路距离,则最短路图上\(u\)到\(v\)也连一条相同的边

然后模拟一遍走最小的点就好了

结果跑了个rank倒2,看他们直接倒着一遍dij就完了,现在还搞不懂为什么...

另外我用了一次DFS就直接爆栈了,全改成了BFS

代码

/*
  code by RyeCatcher
*/
const int maxn=800005;
const ll inf=1e17+19260817;
struct Edge{
    int ne,to,o;
    ll dis;
}edge[maxn<<1];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to,ll c,int o){
    edge[++num_edge].ne=h[f];
    edge[num_edge].to=to;
    edge[num_edge].dis=c;
    edge[num_edge].o=o;
    h[f]=num_edge;
}
int n,m,tag[maxn];
ll dis[maxn][2],all_dis;
struct SE{
    int ne,to;
    ll dis;
}se[maxn<<1];
int sh[maxn],num_se=1;
inline void add_se(int f,int to,ll c){
    se[++num_se].ne=sh[f];
    se[num_se].to=to;
    se[num_se].dis=c;
    sh[f]=num_se;
}
bool vis[maxn];int g[maxn][2];
inline void dijsktra(int st,int id){
    Heap q;int u,v;
    for(ri i=1;i<=n;i++)dis[i][id]=inf,vis[i]=0;
    while(q.size())q.pop();
    q.push(pii(0,st));dis[st][id]=0,g[st][id]=1;
    while(q.size()){
        u=q.top().second;q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(ri i=h[u];i;i=edge[i].ne){
            v=edge[i].to;
            if(edge[i].o!=id)continue;
            if(dis[v][id]>dis[u][id]+edge[i].dis){
                dis[v][id]=dis[u][id]+edge[i].dis;
                g[v][id]=1;
                q.push(pii(dis[v][id],v));
            }
        }
    }
    return ;
}
void pre_bfs(){
    int u,v;
    queue<int> q;
    q.push(1);memset(vis,0,sizeof(vis));
    while(q.size()){
        u=q.front();q.pop();
        vis[u]=1;
        for(ri i=h[u];i;i=edge[i].ne){
            v=edge[i].to;
            if(dis[u][0]+dis[v][1]+edge[i].dis==all_dis){
                add_se(u,v,edge[i].dis);
                if(!vis[v]){
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
    return ;
}
int path[maxn],tot=0;
inline void bfs(){
    queue <int> q;
    memset(vis,0,sizeof(vis));
    q.push(1);
    int path[maxn],tot=0;
    int u,v,tt,vv,dist=0,dd;
    while(q.size()){
        u=q.front();q.pop();vis[u]=1;
        path[++tot]=tag[u];
        if(u==n){
            printf("%lld\n",all_dis);
            for(ri i=1;i<=tot;i++)printf("%d ",path[i]);
            puts("");
            exit(0);
        }
        tt=1e9+7,vv=0;
        for(ri i=sh[u];i;i=se[i].ne){
            v=se[i].to;
            if(v==n){
                vv=v,dd=se[i].dis;
                break;
            }
            if(vis[v]||!(g[v][1]&&g[v][0]))continue;
            if(tag[v]<tt){
                tt=tag[v],vv=v,dd=se[i].dis;
            }
        }
        if(!vv)break;
        q.push(vv),dist+=dd;
    }
}
int main(){
    int x,y,z;
    //freopen("journalist7.in","r",stdin);
    //freopen("wtf.out","w",stdout);
    read(n),read(m);
    for(ri i=1;i<=n;i++){
        read(tag[i]);
    }
    for(ri i=1;i<=m;i++){
        read(x),read(y),read(z);
        add_edge(x,y,z,0);
        add_edge(y,x,z,1);
    }
    dijsktra(1,0),dijsktra(n,1);
    all_dis=dis[n][0];
    pre_bfs();
    bfs();
    return 0;
}

原文地址:https://www.cnblogs.com/Rye-Catcher/p/9883788.html

时间: 2024-11-05 15:57:04

[JZOJ5279]香港记者题解--最短路图的相关文章

香港记者

Description 众所周知,香港记者跑得比谁都快,这其中其实是有秘诀的.首先他们会跑最短路,但是最短路会有很多条,而且其他记者也知道要跑最短路,香港记者还统计出了每座城市带黑框眼镜的人数,如果一个记者跑路的时候城市带黑框眼镜人数的序列字典序比另一个记者大,那么这个记者就会被不可描述的力量续走时间,导致他跑得没字典序小的记者快.长者日续万秒日理万机,想请你告诉他香港记者经过的总路程和城市带黑框眼镜人数的序列,方便他找到香港记者,传授他们一些人生经验.方便起见,设起点为 1 终点为 n.由于续

[HAOI2012] 道路 - 最短路图,拓扑排序,dp

给定一个无向图,一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它们包含的道路序列不同.我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路.\(n\leq 1500,m\leq 5000,w\leq 10000\) Solution 枚举每个点作为起点,跑出最短路径图,对其拓扑排序后,DP 统计出每个点发出和从起点到达该点的最短路的总数,然后扫一遍所有边统计答案即可. 注意可能有重边 #include <bit

SP338ROADS题解--最短路变式

题目链接 https://www.luogu.org/problemnew/show/SP338 分析 联想到不久前做过的一道题\(Full\) \(Tank\),感觉可以用优先队列做,于是写了\(dijsktra\)(非负权图不敢用\(SPFA\)了) 然后发现错了,想了挺久,发现它实际上是可以找\(dis\)更大的走以花费更少的钱,于是把\(vis\)数组和\(dis\)数组全去掉就A了 优先队列保证取出的距离是最短的,如果距离相同,那么钱数是最小的,所以第一次取出\(n\)时就是答案,跑得

P1144 最短路计数 题解 最短路应用题

题目链接:https://www.luogu.org/problem/P1144 其实这道题目是最短路的变形题,因为数据范围 \(N \le 10^6, M \le 2 \times 10^6\) ,所以直接用Dijkstra算法是不行的,可以使用 Dijkstra+堆优化 或者 SPFA算法来实现. 我这里使用 SPFA算法 来实现 (不会Dijkstra堆优化囧) 这道题目因为需要计数,所以需要在dist数组基础上再开一个cnt数组,其含义如下: \(dist[u]\) :起点 \(1\)

luogu P2149 [SDOI2009]Elaxia的路线 |最短路+建最短路图+卡常数

题目描述 最近,Elaxia 和 w** 的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们必须合理地安排两个人在一起的时间. Elaxia 和 w** 每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长. 现在已知的是 Elaxia 和 w** 所在的宿舍和实验室的编号以及学校的地图: 地图上有 n 个路口,m 条路,经过每条路都需要一定的时间. 具体地说,就是要求无向图中,两对点间最短路的最长公共路径. 输入格式 第一行两个正整数 n,m,表示点

【BZOJ1266】【AHOI2006】上学路线route 最短路建图转最小割

题解: 首先那个裸的单源最短路过程就过了吧. 然后说转的最小割. 就是我们考虑到从源点到汇点有多条最短路,我们需要切断一些边,使得所有的最短路都被切断. 首先这是个很裸的模型,切断?最小割! 如果你想不到,那不妨这么想: 我们切断所有最短路,那么每条最短路都有一个路径,上面有若干条边,那么我们需要至少切断其中的一部分. 而所有的局部最短路都满足一个性质: 就是从源点到某点的最短路长度固定(这个很显然吧,都"最"短了) 那么我们让所有的最短路径都被切断,就会使得一些在最短路径之一的边被切

Bzoj 2763: [JLOI2011]飞行路线 拆点,分层图,最短路,SPFA

2763: [JLOI2011]飞行路线 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1694  Solved: 635[Submit][Status][Discuss] Description Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格.Alice和Bob现在要从一个城市沿着航线到达另一个城市

「JLOI2011」「LuoguP4568」飞行路线(分层图最短路

题目描述 Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在nn个城市设有业务,设这些城市分别标记为00到n-1n−1,一共有mm种航线,每种航线连接两个城市,并且航线有一定的价格. Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机.航空公司对他们这次旅行也推出优惠,他们可以免费在最多kk种航线上搭乘飞机.那么Alice和Bob这次出行最少花费多少? 输入输出格式 输入格式: 数据的第一行有三个整数,n,m,kn,m,k,分别表示城市

BZOJ2763 JLOI2011 飞行路线 最短路

题意:给定一张图,有可以将K条路径的花费变为0,求从1到N的最短路 题解: 分层图+最短路水过. 我们把原图复制K份,平行的放在一起(就像饼干一样一层层的),然后给每个图编号1 2 3……K,然后对于原图中每一条边(x,y),在i的x和i+1的y之间连一条边权为0的边,然后在这K个图上做最短路即可. 当然这只是个思想,实际上你只需要多开一维记录在哪个层里即可,不用真的再去开N*(K-1)个点. #include <queue> #include <cstdio> #include