首先我们可以这么搞...倒序建图,算出源点s附近的点距离终点的距离,然后判断一下,终点是否能跑到源点

能跑到的话呢,我们就判断s周围的点是否在最短路上,然后我们选编号最小的点就好了

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
const int maxn=1005;
const int INF=1e9;
int n,m,dist[maxn],pre[maxn];bool vis[maxn];
struct node{
int v,w;node(){};node(int v,int w):v(v),w(w){};
};
bool cmp(node a,node b){
return a.v<b.v;
}
vector<node> G[maxn];
vector<node> St;
void init(){
for(int i=0;i<maxn;++i) G[i].clear();St.clear();
for(int i=0;i<maxn;++i) dist[i]=INF;
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
}
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
init();int a,b,c;
for(int i=0;i<m;++i){
scanf("%d%d%d",&a,&b,&c);
G[b].push_back(node(a,c));
if(a==0) St.push_back(node(b,c));
//G[b].push_back(node(a,c));
}
queue<int> Q;Q.push(n+1);vis[n+1]=1;dist[n+1]=0;
while(Q.size()){
int now=Q.front();Q.pop();vis[now]=0;
for(int i=0;i<G[now].size();++i){
int to=G[now][i].v,tw=G[now][i].w;
if(dist[to]>dist[now]+tw){
dist[to]=dist[now]+tw;
pre[to]=now;
if(!vis[to]) {
Q.push(to);vis[to]=1;
}
}
}
}
if(dist[0]==INF) {
printf("-1\n");continue;
}
int flag=0,ans=INF;
for(int i=0;i<St.size();++i){
int to=St[i].v,tw=St[i].w;
if(tw+dist[to]==dist[0]){
if(to==n+1){
flag=1;break;
}
ans=min(ans,to);
}
}
if(flag) printf("0\n");
else printf("%d\n",ans);
}
return 0;
}

下面这种做法是错误做法,那就是先对每个邻接表按顶点标号大小排序,然后跑一遍spfa

一般的数据都能正常出解,但是对于这一组数据,哈哈,怕是翻车了

2 4
0 1 2
1 2 1
0 2 3
2 3 1

松弛完1,直接松弛0,2这条边,于是0,1,2,3这条路径不会被考虑了,

于是答案就是2,而不是正确的1,1被早来的0,2这条边从后面架空了

附上错误代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
const int maxn=1005;
const int INF=1e9;
int n,m,dist[maxn],pre[maxn];bool vis[maxn];
struct node{
int v,w;node(){};node(int v,int w):v(v),w(w){};
};
bool cmp(node a,node b){
return a.v<b.v;
}
vector<node> G[maxn];
void init(){
for(int i=0;i<maxn;++i) G[i].clear();
for(int i=0;i<maxn;++i) dist[i]=INF;
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
}
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
init();int a,b,c;
for(int i=0;i<m;++i){
scanf("%d%d%d",&a,&b,&c);
G[a].push_back(node(b,c));
//G[b].push_back(node(a,c));
}
for(int i=0;i<maxn;++i){
if(G[i].size()) sort(G[i].begin(),G[i].end(),cmp);
}
queue<int> Q;Q.push(0);vis[0]=1;dist[0]=0;
while(Q.size()){
int now=Q.front();Q.pop();vis[now]=0;
for(int i=0;i<G[now].size();++i){
int to=G[now][i].v,tw=G[now][i].w;
if(dist[to]>dist[now]+tw){
dist[to]=dist[now]+tw;
pre[to]=now;
if(!vis[to]) {
Q.push(to);vis[to]=1;
}
}
}
}
if(dist[n+1]==INF) {
printf("-1\n");continue;
}
int i;
for(i=0;i<G[0].size();++i) {
if(G[0][i].v==n+1&&G[0][i].w==dist[n+1]) break;
}
if(i<G[0].size()) {printf("0\n");continue;}
for(i=n+1;pre[i]!=0;i=pre[i]);
printf("%d\n",i);
}
return 0;
}

由于路径不算原点,所以说

0 2 3>0 1 2 3

也就是 2 3>1 2 3

所以在源点需要特判

然后还有一个要注意地方

有一种因为数据弱而能ac的错误做法,在求最短路的过程中,尝试使它的前驱变小

这样做的缺陷在于,你没法保留当前前驱大但是字典序小的路径,这种做法的代码如下

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<utility>
#include<queue>
using namespace std;
#define mp make_pair
#define X first
#define Y second
const int N=1008;
const int M=1000000008;
int n,m;
vector<pair<int,int> >a[N];
int b[N],c[N],flag[N];
queue<int>d;
int main(void)
{
int t,i,k,p1,p2,p3;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=0;i<=n+1;i++)a[i].clear();
while(m--){scanf("%d%d%d",&p1,&p2,&p3);a[p1].push_back(mp(p2,p3));}
for(i=0;i<=n+1;i++){b[i]=c[i]=M;flag[i]=0;}
while(!d.empty()){d.pop();}d.push(0);b[0]=c[0]=0;flag[0]=1;
while(!d.empty())
{
k=d.front();d.pop();flag[k]=0;
for(i=0;i<(int)a[k].size();i++)
if((b[a[k][i].X]>b[k]+a[k][i].Y)||(b[a[k][i].X]==b[k]+a[k][i].Y&&c[a[k][i].X]>k))
{
b[a[k][i].X]=b[k]+a[k][i].Y;
c[a[k][i].X]=k;
if(flag[a[k][i].X]==0){flag[a[k][i].X]=1;d.push(a[k][i].X);}
}
}
if(b[n+1]==M){printf("-1\n");continue;}
for(i=0;i<(int)a[0].size();i++)if(a[0][i].X==n+1&&a[0][i].Y==b[n+1])break;
if(i<(int)a[0].size()){printf("0\n");continue;}
k=n+1;while(c[k])k=c[k];
printf("%d\n",k);
}
return 0;
}

除了逆向建图的做法之外,我们可以正向先跑出一个最短距离

然后把s的邻接点全部按编号排序,从s的邻接点挨个跑一遍s'到t的最短路,看该点在不在最短路上

找到的第一个解就是答案,附上代码

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<utility>
#include<queue>
#include<algorithm>
using namespace std;
#define mp make_pair
#define X first
#define Y second
const int N=1008;
const int M=1000000008;
int n,m;
vector<pair<int,int> >a[N];
int b[N],flag[N];
queue<int>d;
int main(void)
{
int t,i,k,p1,p2,p3;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=0;i<=n+1;i++)a[i].clear();
while(m--){scanf("%d%d%d",&p1,&p2,&p3);a[p1].push_back(mp(p2,p3));}
for(i=0;i<=n+1;i++){b[i]=M;flag[i]=0;}
while(!d.empty()){d.pop();}d.push(0);b[0]=0;flag[0]=1;
while(!d.empty())
{
k=d.front();d.pop();flag[k]=0;
for(i=0;i<(int)a[k].size();i++)if(b[a[k][i].X]>b[k]+a[k][i].Y)
{
b[a[k][i].X]=b[k]+a[k][i].Y;
if(flag[a[k][i].X]==0){flag[a[k][i].X]=1;d.push(a[k][i].X);}
}
}
p3=b[n+1];
if(b[n+1]==M){printf("-1\n");continue;}
for(i=0;i<(int)a[0].size();i++)if(a[0][i].X==n+1&&a[0][i].Y==b[n+1])break;
if(i<(int)a[0].size()){printf("0\n");continue;}
sort(a[0].begin(),a[0].end());
for(p1=0;p1<(int)a[0].size();p1++)
{
for(i=0;i<=n+1;i++){b[i]=M;flag[i]=0;}
while(!d.empty()){d.pop();}d.push(a[0][p1].X);b[a[0][p1].X]=0;flag[a[0][p1].X]=1;
while(!d.empty())
{
k=d.front();d.pop();flag[k]=0;
for(i=0;i<(int)a[k].size();i++)if(b[a[k][i].X]>b[k]+a[k][i].Y)
{
b[a[k][i].X]=b[k]+a[k][i].Y;
if(flag[a[k][i].X]==0){flag[a[k][i].X]=1;d.push(a[k][i].X);}
}
}
if(b[n+1]+a[0][p1].Y==p3)break;
}
printf("%d\n",a[0][p1].X);
}
return 0;
}

sdut3562-求字典序最小的最短路 按顶点排序后spfa的反例的更多相关文章

  1. HDU 5915 The Fastest Runner Ms. Zhang (CCPC2016 长春 E题,分类讨论 + 求字典序最小的直径 + 数据结构寻找最小值)

    题目链接  CCPC2016 Changchun Problem E 题意  给定一个$n$个点$n$条边的无向图,现在从某一点$s$出发,每个点都经过一遍,最后在$t$点停止,经过的边数为$l$   ...

  2. UVa 1599 (字典序最小的最短路) Ideal Path

    题意: 给出一个图(图中可能含平行边,可能含环),每条边有一个颜色标号.在从节点1到节点n的最短路的前提下,找到一条字典序最小的路径. 分析: 首先从节点n到节点1倒着BFS一次,算出每个节点到节点n ...

  3. POJ 2337 Catenyms (有向图欧拉路径,求字典序最小的解)

    Catenyms Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8756   Accepted: 2306 Descript ...

  4. [poj2337]求字典序最小欧拉回路

    注意:找出一条欧拉回路,与判定这个图能不能一笔联通...是不同的概念 c++奇怪的编译规则...生不如死啊... string怎么用啊...cincout来救? 可以直接.length()我也是长见识 ...

  5. HDU1385 【输出字典序最小的最短路】

    这题经过的结点比较好处理. 主要是字典序的处理. 先是floyd做法,采用记录后驱的方法.  path[i][j]=j[初始化...] #include <iostream> #inclu ...

  6. Floyd求字典序最小的路径

    hdu1384 Minimum Transport Cost Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  7. 图论--2-SAT--暴力染色法求字典序最小模版

    #include <cstdio> #include <cstring> #include <stack> #include <queue> #incl ...

  8. 偶然在博客中见对百度一个面试题的探讨,写些自己的看法以及指出探讨中不对的观点:百度面试题:求绝对值最小的数 有一个已经排序的数组(升序),数组中可能有正数、负数或0,求数组中元素的绝对值最小的数,要求,不能用顺序比较的方法(复杂度需要小于O(n)),可以使用任何语言实现 例如,数组{-20,-13,-4, 6, 77,200} ,绝对值最小的是-4。

    今天申请了博客园账号,在下班后阅览博客时发现了一个关于百度面试题探讨的博客(其实是个很基础的问题),此博客url为:http://www.blogjava.net/nokiaguy/archive/2 ...

  9. BZOJ1046 [HAOI2007]上升序列 【LIS + 字典序最小】

    1046: [HAOI2007]上升序列 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 5410  Solved: 1877 [Submit][St ...

随机推荐

  1. 【中文】【deplearning.ai】【吴恩达课后作业目录】

    [目录][吴恩达课后作业目录] 吴恩达深度学习相关资源下载地址(蓝奏云) 课程 周数 名称 类型 语言 地址 课程1 - 神经网络和深度学习 第1周 深度学习简介 测验 中英 传送门 无编程作业 编程 ...

  2. moco框架加入cookies

    一.带cookie信息的get请求 注意:cookie是放在request里的,一般登录的场景这些会用到 1.代码 2.接口管理工具添加 注意:cooike的域和路径都要添加 二.带cookie信息的 ...

  3. 在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

    在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态.这些都是计算属性无法做到的.

  4. 可视化Go内存管理

    小结: 1. Go不需要VM,Go应用程序二进制文件中嵌入了一个小型运行时(Go runtime),可以处理诸如垃圾收集(GC),调度和并发之类的语言功能 Go does not need a VM ...

  5. Centos虚拟机上安装部署Tenginx,以及部署过程中遇到的问题

    Tenginx下载网址: Tenginx 官网地址:http://tengine.taobao.org/ Tenginx的官方网址中可以阅读Nginx的文档,可以选择中文进行阅读.下载Tengine- ...

  6. QT串口助手(四):数据发送

    作者:zzssdd2 E-mail:zzssdd2@foxmail.com 一.前言 开发环境:Qt5.12.10 + MinGW 实现的功能 串口数据的发送 ascii字符与hex字符的相互转换 自 ...

  7. 【算法】ST表

    想学习一下LCA倍增,先 水一个黄题 学一下ST表 ST表 介绍: 这是一个运用倍增思想,通过动态规划来计算区间最值的算法 算法步骤: 求出区间最值 回答询问 求出区间最值: 用f[i][j]来存储从 ...

  8. loj10161 叶子的颜色

    CQOI 2009 给一棵有 mm 个节点的无根树,你可以选择一个度数大于 11 的节点作为根,然后给一些节点(根.内部节点.叶子均可)着以黑色或白色.你的着色方案应保证根节点到各叶子节点的简单路径上 ...

  9. markdown编辑器typora本地图片上传到自己的服务器

    typora是windows平台下最受欢迎的markdown书写工具和查看工具,本篇文章将会介绍如何在typora平台使用java脚本程序自动上传本地图片到自己的服务器,从而让markdown文章中的 ...

  10. P6686 混凝土数学

    哈哈哈!我爱月赛. 第一次月赛拿到分呢. (卡掉卡掉) 题目描述 你正在看混凝土数学,这时旁边的工地开工了,你觉得看他们施工更有意思,于是你向窗外望去,注意到了一些长度不同的木棍.具体而言,你看到了  ...