sdut3562-求字典序最小的最短路 按顶点排序后spfa的反例

首先我们可以这么搞...倒序建图,算出源点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

所以在源点需要特判

时间: 2024-12-16 08:53:23

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

hdu 1385 求字典序最小的最短路

需要注意的是这个题不仅有边权还有点权,起点和终点的点权不算. 思路还是一样,只是把路过的点的点权也加上再松弛即可.另外,距离相等的时候需要判断一下,选择字典序小的链连到这个点,方法就是把这个点以及之前的点放到栈里比较. 1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <stack> 5 #include <cstdio> 6 using na

HDU 5335 Walk Out(Bfs搜索字典序最小的最短路)

 题意:nXm的地图, 问通过四个方向从(1,1)走到(1000,1000)所经过的最小二进制序列是多少,忽略前缀0. 思路:首先如果起点为0,那么我们bfs搜索和起点0联通的为0的连通块,这样我们第一步肯定是从与这个连通块相邻的且与重点最近的地方出发. 将所有可能起点加入队列,在bfs一遍找到字典序最小的那条路就是答案, 在这里可以用两个vector类型容器,一个是q2存储所有节点值存为0的结点, 另一个q3存储节点值为1的结点. 那么如果q2不为空那么也就是有可以走零,那么就从这里面选,

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

注意:找出一条欧拉回路,与判定这个图能不能一笔联通...是不同的概念 c++奇怪的编译规则...生不如死啊... string怎么用啊...cincout来救? 可以直接.length()我也是长见识了... CE怎么办啊...g++来救? #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #define N 2020

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

今天申请了博客园账号,在下班后阅览博客时发现了一个关于百度面试题探讨的博客(其实是个很基础的问题),此博客url为:http://www.blogjava.net/nokiaguy/archive/2013/01/30/394920.html 其中下面有人评论为: 有序列表查找显然二分啊,博主貌似对java的arrays和collections不是很熟. private static int getMinAbsoluteValue(final int[] source) { int index

HDU - 3035 War(对偶图求最小割+最短路)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3035 题意 给个图,求把s和t分开的最小割. 分析 实际顶点和边非常多,不能用最大流来求解.这道题要用平面图求最小割的方法: 把面变成顶点,对每两个面相邻的边作一条新边.然后求最短路就是最小割了. 另外,外平面分成两个点,分别是源点和汇点,源点连左下的边,汇点连右上的边,这样跑出来才是正确的. 建图参考自:https://blog.csdn.net/accelerator_/article/deta

hdu1385 Minimum Transport Cost 字典序最小的最短路径 Floyd

求最短路的算法最有名的是Dijkstra.所以一般拿到题目第一反应就是使用Dijkstra算法.但是此题要求的好几对起点和终点的最短路径.所以用Floyd是最好的选择.因为其他三种最短路的算法都是单源的. 输出字典序最小的路径则需要修改模版. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N =1

贪心:字典序最小问题

*/--> pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;} 贪心:字典序最小问题 给定长度为 n 的字符串 s,要构造一个长度为 n 的字符串 t.起初,t 是一个空串,随后反复进行下列操作 1. 从 s 的头部删除一个字符,加到 t 的尾部 2. 从 s 的尾部删除一个字符,加到 t 的尾部 求 t 是字典序尽可能小的字符串 示例: n = 6 s

BZOJ 2007 海拔(平面图最小割-最短路)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2007 题意:给出一个n*n的格子,那么顶点显然有(n+1)*(n+1)个.每两个相邻顶点之间有两条边,这两条边是有向的,边上有权值..左上角为源点,右下角为汇点,求s到t的最小割. 思路:很明显这是一个平面图,将其转化为最 短路.我们将s到t之间连一条边,左下角为新图的源点S,右上角区域为新图的终点T,并且为每个格子编号.由于边是有向的,我们就要分析下这条边应该是哪 个点向哪个点的边.

poj 1815 Friendship 字典序最小+最小割

题目链接:http://poj.org/problem?id=1815 In modern society, each person has his own friends. Since all the people are very busy, they communicate with each other only by phone. You can assume that people A can keep in touch with people B, only if 1. A kno