因为题面实在是太过暴力,就不贴链接了……我自己重新写一下题面吧……

题目描述

给定一张带权有向图,设起点为1,终点为n,每个点除编号外还有一个序号,要求输出从起点至终点的最短路经过的点的序号和最短距离,如果两点之间有多条最短路,输出字典序最小的。

数据范围

对于30%的数据,\(2\leq n\leq 2\cdot 10^3,1\leq m\leq 4\cdot 10^3\)。

对于60%的数据,保证数据随机。

对于100%的数据,\(2\leq n\leq 2\cdot 10^5,1\leq m\leq 4\cdot 10^5,1\leq w\leq 10^9\)。存在至少一条从1至n的最短路。


题解

30分做法

感觉这个部分分一点意思都没有啊……可能是为那些只会写\(O(n^2)\)dijkstra算法,连SPFA都不会的人准备的吧……

60分做法

由于不存在负权边,可以使用堆优化的dijkstra算法。由于要输出字典序最小的路径,我们需要记录从点1到点i的最短路中字典序最小的路径,这个可以用vector保存。在松弛时如果\(dis_{v}=dis_{u}+w_{u,v}\),就暴力对两条路径进行比较,最后更新为字典序较小的那个。由于每次松弛时复杂度最坏可能达到\(O(n)\),所以总复杂度最坏可能为\(O(n^{2}log_{n})\),一张网格图就可以轻松卡掉。然而前60%的数据均为随机,所以比较两路径的概率极小,所以复杂度还是偏向\(O(nlog_{n})\)的。

代码

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=2e5+10,maxm=4e5+10;
typedef pair<LL,int>pii;
priority_queue<pii,vector<pii>,greater<pii> >pq;
int heade[maxn],ev[maxm],ew[maxm],nexte[maxm];
int dw[maxn];
LL dis[maxn];
vector<int>pre[maxn];
int n,m,tot=0,s,t;
void add_edge(int u,int v,int w){tot++;ev[tot]=v;ew[tot]=w;nexte[tot]=heade[u];heade[u]=tot;}
int cmp(vector<int>a,vector<int>b)
{
int i,flag,len1,len2;
len1=a.size();len2=b.size();flag=len1<len2?0:1;
for(i=0;i<min(len1,len2);i++){if(a[i]<b[i]){return 0;}else if(a[i]>b[i]){return 1;}}
return flag;
}
void dijkstra()
{
int i,ui,vi,wi;pii u;vector<int>tmp;
dis[s]=0;pq.push(make_pair(dis[s],s));pre[s].push_back(dw[s]);
while(!pq.empty())
{
u=pq.top();pq.pop();ui=u.second;
for(i=heade[ui];~i;i=nexte[i])
{
vi=ev[i];wi=ew[i];tmp=pre[ui];
if(dis[vi]<dis[ui]+wi){continue;}
tmp.push_back(dw[vi]);
if(dis[vi]>dis[ui]+wi)
{
dis[vi]=dis[ui]+wi;
pre[vi]=tmp;
}
else if(!cmp(tmp,pre[vi])){pre[vi]=tmp;}
pq.push(make_pair(dis[vi],vi));
}
}
}
int main()
{
int i,j,u,v,w;
cin>>n>>m;s=1;t=n;
memset(heade,-1,sizeof(heade));memset(dis,127,sizeof(dis));
for(i=1;i<=n;i++){scanf("%d",&dw[i]);}
for(i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);add_edge(u,v,w);}
dijkstra();
cout<<dis[t]<<endl;
for(i=0;i<(int)pre[t].size();i++){printf("%d ",pre[t][i]);}cout<<endl;
return 0;
}

100分做法

考虑到我们并不是要求出从起点到每个点的字典序最小的最短路径,所以在这方面进行优化。

先跑一遍堆优化dijkstra,求出从起点到每个点的最短路,然后枚举每条边,如果对于一条边\((u,v,w)\exists dis_{v}=dis_{u}+w\),那么这条边一定在从起点到终点的某条最短路中。我们相当于把其他的边删去,保留一个子图。真正的操作方法是在原有基础上构建一个新图,然后在新图上进行BFS或DFS,由于要求字典序最小,构图时最好使用vector,遍历前将每个点的邻接点根据序号进行排序,遍历时再记录每个点的前驱,这样搜到终点时就可以输出整条路径了。总复杂度\(O(nlog_{n}+m)\)。

代码

#include<bits/stdc++.h>
#define LL long long
using namespace std;
typedef pair<LL,int>pii;
priority_queue<pii,vector<pii>,greater<pii> >pq;
const int maxn=2e5+10,maxm=4e5+10;
int heade[maxn],eu[maxm],ev[maxm],ew[maxm],nexte[maxm];
LL dis[maxn];
int dw[maxn],pre[maxn],isvis[maxn],rec[maxn];
struct dot{int id,d;};
vector<dot>link[maxn];
int n,m,tot=0,s,t,num=0,flag=0;
int cmp(dot a,dot b){return a.d<b.d;}
void add_edge(int u,int v,int w){tot++;eu[tot]=u;ev[tot]=v;ew[tot]=w;nexte[tot]=heade[u];heade[u]=tot;}
void dijkstra()
{
int i,ui,vi,wi;pii u;
dis[s]=0;pq.push(make_pair(dis[s],s));
while(!pq.empty())
{
u=pq.top();pq.pop();ui=u.second;
for(i=heade[ui];~i;i=nexte[i])
{
vi=ev[i];wi=ew[i];
if(dis[vi]<=dis[ui]+wi){continue;}
dis[vi]=dis[ui]+wi;
pq.push(make_pair(dis[vi],vi));
}
}
printf("%lld\n",dis[t]);
}
void dfs(int ui)
{
int i,vi,di;
if(flag){return;}
isvis[ui]=1;
if(ui==t)
{
flag=1;
for(i=t;i!=s;i=pre[i]){rec[++num]=dw[i];}rec[++num]=dw[s];
for(i=num;i>=1;i--){printf("%d ",rec[i]);}cout<<endl;
return;
}
for(i=0;i<(int)link[ui].size();i++)
{
if(flag){break;}
vi=link[ui][i].id;di=link[ui][i].d;
if(isvis[vi]){continue;}
pre[vi]=ui;
dfs(vi);
}
}
int main()
{
int i,j,u,v,w;
cin>>n>>m;s=1;t=n;
memset(heade,-1,sizeof(heade));memset(dis,127,sizeof(dis));
for(i=1;i<=n;i++){scanf("%d",&dw[i]);}
for(i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);add_edge(u,v,w);}
dijkstra();
for(i=1;i<=m;i++)
{
u=eu[i];v=ev[i];w=ew[i];
if(dis[u]+w==dis[v]){link[u].push_back((dot){v,dw[v]});}
}
for(i=1;i<=n;i++){sort(link[i].begin(),link[i].end(),cmp);}
dfs(s);
return 0;
}

SCZ 20170812 T1 HKJ的更多相关文章

  1. SCZ 20170812 T2 MFS

    题面照例十分暴力,我再次重写一下吧-- 题目描述 有\(n\)个数构成的数列\(A\)元素为\(a_i\),你要构造一个数列\(B\),元素为\(b_i\),使得满足\(b_{i}>0,a_{i ...

  2. group_concat() 函数 拼接字符串长度有限制

    最近,在做一个行转列的存储过程,遇到一个问题,问题如下: 我用group_concat()函数 来整合一个月每天的操作量,并将每天的操作量用CONCAT()函数拼接成 “MAX(IF(t.a = '2 ...

  3. T1加权像(T1 weighted image,T1WI)

    T1加权成像(T1-weighted imaging,T1WI)是指这种成像方法重点突出组织纵向弛豫差别,而尽量减少组织其他特性如横向弛豫等对图像的影响. 弛豫:物理用语,从某一个状态恢复到平衡态的过 ...

  4. 关于2016.12.12——T1的反思:凸包的意义与应用

    2016.12.12 T1 给n个圆,保证圆圆相离,求将圆围起来的最小周长.n<=100 就像上图.考场上,我就想用切线的角度来做凸包.以圆心x,y排序,像点凸包一样,不过用两圆之间的下切线角度 ...

  5. T2 Func<in T1,out T2>(T1 arg)

    委托调用方法的4种方式. using System; using System.Collections.Generic; namespace ConsoleApplication1 { delegat ...

  6. E1、T1链路

    北美的24路脉码调制PCM简称T1 速率是1.544Mbit/s 北美使用的T1系统共有24个话路,每个话路采样脉冲用7bit编码,然后再加上1位信令码元,因此一个话路占用8bit. 帧同步码是在24 ...

  7. Action<T1, T2>委托

    封装包含两个参数的方法委托,没有返回值. 语法 public delegate void Action<in T1, in T2>( T1 arg1, T2 arg2 ) 类型参数 in ...

  8. 有三个线程T1 T2 T3,如何保证他们按顺序执行-转载

    T3先执行,在T3的run中,调用t2.join,让t2执行完成后再执行t3 在T2的run中,调用t1.join,让t1执行完成后再让T2执行 public class Test { // 1.现在 ...

  9. 现在有T1、T2、T3三个线程,怎样保证T2在T1执行完后执行,T3在T2执行完后执行?使用Join

    public class TestJoin { public static void main(String[] args) { Thread t1 = new Thread(new T1(), &q ...

随机推荐

  1. Python在项目外更改项目内引用

    前言 目前有一个奇葩的需求, 将某个开源项目整合进自己的项目里去调度, 还需要在每次启动这个开源项目时, 加载不同的配置文件进去, 问题是配置文件并不是一个 conf 或者是其他的什么, 而是以 .p ...

  2. 分装button组件引发的内存泄漏问题

    这个问题其实一开始在vue里写的时候并没有注意到这一点,也没有报错,直到在react里写的时候给我报了一堆错之后,经各种磨烂之后最终找到是分装button组件的问题,既然找到问题在哪就好办了 直接先上 ...

  3. python学习笔记 | PyCharm创建文件时自动添加头文件

    File Settings Editor File and Code Templates Python Script 然后在右边的框中写入信息就可以啦: # -*- coding: utf-8 -*- ...

  4. 【ASM】asm中添加 diskgroup

    环境:rhel5 Oracle10g rac 背景:在esxi中添加了一个20g的共享磁盘准备存放归档日志用 一.准备环境 1.添加共享磁盘并且格式化 #fdisk -l查看磁盘已经添加完成 #fdi ...

  5. leetcode刷题录-1395

    目录 题目 思考过程 查看别人分享的思路 总结 题目 题目地址:https://leetcode-cn.com/problems/count-number-of-teams/ n 名士兵站成一排.每个 ...

  6. C++:I/O流的概念和流类库的结构

    一.C++输入输出包含以下三个方面的内容: 对系统指定的标准设备的输入和输出.即从键盘输入数据,输出到显示器屏幕.这种输入输出称为标准的输入输出,简称标准I/O. 以外存磁盘文件为对象进行输入和输出, ...

  7. 多路复用器Select、Poll、Epoll区别梳理

    注意:本文是本人的学习总结,可能存在理解上的错误,请带着怀疑眼光看待,如果有不准确的地方欢迎指出,疑义相与析.为了叙述完整性,前面有一些前置知识,可以根据目录直接看后面的详解部分. 前置知识 用户态与 ...

  8. 关于Java客户端连接虚拟机中的Kafka时,无法发送、接收消息的问题

    kafka通过控制台模拟消息发送和消息接收正常,但是通过javaAPI操作生产者发送消息不成功 消费者接收不到数据解决方案? 1.问题排查 (1)首先通过在服务器上使用命令行来模拟生产.消费数据,发现 ...

  9. Redis 底层数据结构设计

    10万+QPS 真的只是因为单线程和基于内存?_Howinfun的博客-CSDN博客_qps面试题 https://blog.csdn.net/Howinfun/article/details/105 ...

  10. Springboot中PropertySource注解的使用

    https://blog.csdn.net/qq_30739519/article/list/3 注解 https://blog.csdn.net/qq_30739519/article/detail ...