【最短路-SPFA/Dijkstra】Codeforces Round #333 (Div. 2) C. The Two Routes

Codeforces Round #333 (Div. 2) C. The Two Routes

  • 题意:有V个村庄,每两个村庄间都有路(铁路或公路,铁路和公路不重合,也就是说有铁路就没有公路),其中铁路有E条,让我们求从村庄1到村庄V的最短路径。如果沿着铁路走到不了或者沿着公路走到不了都输出-1,如果沿着铁路走和沿着公路走其各自最短路径的时间不一样,那就输出较大者。所有路径的边权都为1。
  • 思路:就是跑两个最短路的模板就可以了。就是要注意一下处理好边的情况就可以了,我这里是用的邻接矩阵来判断是不是铁路。

SPFA:
刚刚知道SPFA的一个小优化,就是用stack(后进后出)代替queue(后进前出),会优化一点,十几ms,至于为什么我也不知道,可能是因为后进后出的话会先遍历完所有的点,所以会尽可能地减少重复入队的可能叭。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define P(x) x>0?x:0
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxV=405;
const int maxE=8e4;
int V,E;
bool mp[maxV][maxV];
bool T_inque[maxV],G_inque[maxV];
int T_dis[maxV],G_dis[maxV];
int T_head[maxV],G_head[maxV],T_cnt,G_cnt;
struct EDGE{
    int pre,to;
    EDGE(int a=0,int b=0):pre(a),to(b){}
};
EDGE T_edge[2*maxE];
EDGE G_edge[2*maxE];
void T_add_edge(int u,int v)
{
    T_edge[++T_cnt]=EDGE(T_head[u],v);
    T_head[u]=T_cnt;
}
void G_add_edge(int u,int v)
{
    G_edge[++G_cnt]=EDGE(G_head[u],v);
    G_head[u]=G_cnt;
}
void init()
{
    T_cnt=0;
    G_cnt=0;
    memset(mp, false, sizeof(mp));
    memset(T_head,-1, sizeof(T_head));
    memset(G_head,-1, sizeof(G_head));
}
int T_SPFA(int st,int ed)
{
    for(int i=1;i<=V;i++)
        T_dis[i]=(i==st ? 0 : INF);
    memset(T_inque,false, sizeof(T_inque));
    stack<int >s;
    s.push(st);
    T_inque[st]=true;
    while(!s.empty())
    {
        int tmp=s.top();
        s.pop();
        for(int i=T_head[tmp]; ~i ; i=T_edge[i].pre)
        {
            if(T_dis[T_edge[i].to]>T_dis[tmp]+1)
            {
                T_dis[T_edge[i].to]=T_dis[tmp]+1;
                if(!T_inque[T_edge[i].to])
                {
                    s.push(T_edge[i].to);
                    T_inque[T_edge[i].to]=true;
                }
            }
        }
        T_inque[tmp]= false;
    }
    return T_dis[ed];
}
int G_SPFA(int st,int ed)
{
    for(int i=1;i<=V;i++)
        G_dis[i]=(i==st ? 0 : INF);
    memset(G_inque,false, sizeof(G_inque));
    stack<int >s;
    s.push(st);
    G_inque[st]=true;
    while(!s.empty())
    {
        int tmp=s.top();
        s.pop();
        for(int i=G_head[tmp]; ~i ; i=G_edge[i].pre)
        {
            if(G_dis[G_edge[i].to]>G_dis[tmp]+1)
            {
                G_dis[G_edge[i].to]=G_dis[tmp]+1;
                if(!G_inque[G_edge[i].to])
                {
                    s.push(G_edge[i].to);
                    G_inque[G_edge[i].to]=true;
                }
            }
        }
        G_inque[tmp]= false;
    }
    return G_dis[ed];
}
int main()
{
    while(~scanf("%d%d",&V,&E))
    {
        init();
        for(int i=1;i<=E;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            T_add_edge(min(a,b),max(a,b));
            T_add_edge(max(a,b),min(a,b));
            mp[min(a,b)][max(a,b)]=true;
        }
        for(int i=1;i<=V;i++)
            for(int j=i+1;j<=V;j++)
                if(!mp[i][j])
                {
                    G_add_edge(i,j);
                    G_add_edge(j,i);
                }
        int GE=V*(V-1)/2-E;
        int ansT,ansG;
        if(GE==0||(ansT=T_SPFA(1,V))==INF||(ansG=G_SPFA(1,V))==INF)
            printf("-1\n");
        else
            printf("%d\n",max(ansT,ansG));
    }
    return 0;
}

Dijkstra【链式前向星】:
做了个小小的优化:dij终点取出来就可以直接return了。
然后今天发现dij有些概念模糊叭,反正就是又模拟了一遍dij,重新理解了一下。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define P(x) x>0?x:0
#define INF 0x3f3f3f3f

using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxV=405;
const int maxE=8e4;
int V,E;
bool mp[maxV][maxV];
struct EDGE{
    int pre,to;
    EDGE(int a=0,int b=0):pre(a),to(b){}
};
EDGE T_edge[maxE*2],G_edge[maxE*2];
int T_head[maxV],G_head[maxV],T_cnt,G_cnt;
int T_dis[maxV],G_dis[maxV];
bool T_vis[maxV],G_vis[maxV];
void T_add_edge(int u,int v)
{
    T_edge[++T_cnt]=EDGE(T_head[u],v);
    T_head[u]=T_cnt;
}
void G_add_edge(int u,int v)
{
    G_edge[++G_cnt]=EDGE(G_head[u],v);
    G_head[u]=G_cnt;
}
void init()
{
    T_cnt=0;
    G_cnt=0;
    memset(T_head,-1, sizeof(T_head));
    memset(G_head,-1, sizeof(G_head));
    memset(mp,false, sizeof(mp));
}
struct node{
    int point,val;
    node(int a=0,int b=0):point(a),val(b){}
    friend bool operator < (node n1,node n2) { return n1.val>n2.val; }
};
int T_dijkstra(int st,int ed)
{
    memset(T_vis,false,sizeof(T_vis));
    for(int i=1;i<=V;i++)
        T_dis[i]=(i==st ? 0 : INF);
    priority_queue<node>pq;
    pq.push(node(st,T_dis[st]));
    while(!pq.empty())
    {
        node tmp=pq.top();
        if(tmp.point==ed)
            return T_dis[ed];
        if(T_vis[tmp.point])
            continue;
        pq.pop();
        T_vis[tmp.point]=true;
        for(int i=T_head[tmp.point]; ~i ; i=T_edge[i].pre)
        {
            if(T_dis[T_edge[i].to]>T_dis[tmp.point]+1)
            {
                T_dis[T_edge[i].to]=T_dis[tmp.point]+1;
                pq.push(node(T_edge[i].to,T_dis[T_edge[i].to]));
            }
        }
    }
    return -1;
}
int G_dijkstra(int st,int ed)
{
    memset(G_vis,false,sizeof(G_vis));
    for(int i=1;i<=V;i++)
        G_dis[i]=(i==st ? 0 : INF);
    priority_queue<node>pq;
    pq.push(node(st,G_dis[st]));
    while(!pq.empty())
    {
        node tmp=pq.top();
        if(tmp.point==ed)
            return G_dis[ed];
        if(G_vis[tmp.point])
            continue;
        pq.pop();
        G_vis[tmp.point]=true;
        for(int i=G_head[tmp.point]; ~i ; i=G_edge[i].pre)
        {
            if(G_dis[G_edge[i].to]>G_dis[tmp.point]+1)
            {
                G_dis[G_edge[i].to]=G_dis[tmp.point]+1;
                pq.push(node(G_edge[i].to,G_dis[G_edge[i].to]));
            }
        }
    }
    return -1;
}
int main()
{
    while(~scanf("%d%d",&V,&E))
    {
        init();
        for(int i=1;i<=E;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            T_add_edge(a,b);
            T_add_edge(b,a);
            mp[min(a,b)][max(a,b)]=true;
        }
        for(int i=1;i<=V;i++)
            for(int j=i+1;j<=V;j++)
                if(!mp[i][j])
                {
                    G_add_edge(i,j);
                    G_add_edge(j,i);
                }
        int GE=V*(V-1)/2-E;
        int ansT,ansG;
        if(GE==0||(ansT=T_dijkstra(1,V))==-1||(ansG=G_dijkstra(1,V))==-1)
            printf("-1\n");
        else
            printf("%d\n",max(ansT,ansG));
    }
    return 0;
}

Djikstra【邻接矩阵】
这个题的话,其实是个稠密图,用链式前向星的话空间占据其实很大,也比较麻烦,时间优势差不多也没有多少。这时候用邻接矩阵就比较合适,省空间,也比较好写,一哈就写出来了。(听别人的建议所以补上的,确实比上面两个代码短也合适)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define P(x) x>0 ? x : 0
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr

using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxN=405;
int mp[maxN][maxN],dis[maxN],vis[maxN];
int n,m;
struct node{
    int to,val;
    node(int a=0,int b=0):to(a),val(b){}
    friend bool operator < (node n1,node n2) { return n1.val>n2.val; }
};

int dijkstra(int st,int ed,int road)//铁路是1,公路是0
{
    memset(vis,0, sizeof(vis));
    for(int i=1;i<=n;i++)
        dis[i]=(i==st ? 0 : INF);
    priority_queue<node>pq;
    pq.push(node(st,dis[st]));
    while(!pq.empty())
    {
        node tmp=pq.top();
        pq.pop();
        if(vis[tmp.to])
            continue;
        for(int i=1;i<=n;i++)
        {
            if(mp[tmp.to][i]!=-1)
            {
                if(road && mp[tmp.to][i])//铁路
                {
                    if(dis[i]>dis[tmp.to]+1)
                    {
                        dis[i]=dis[tmp.to]+1;
                        pq.push(node(i,dis[i]));
                    }
                }
                else if(!road && !mp[tmp.to][i])//公路
                {
                    if(dis[i]>dis[tmp.to]+1)
                    {
                        dis[i]=dis[tmp.to]+1;
                        pq.push(node(i,dis[i]));
                    }
                }
            }
        }
        vis[tmp.to]=1;
    }
    return dis[ed];
}

void init()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)
                mp[i][j]=-1;
            else
                mp[i][j]=0;
        }
    }
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int a,b; scanf("%d%d",&a,&b);
            mp[a][b]=1;
            mp[b][a]=1;
        }
        int T=dijkstra(1,n,1);
        int G=dijkstra(1,n,0);
        if(T==INF||G==INF)
            printf("-1\n");
        else
            printf("%d\n",max(T,G));
    }
    return 0;
}

My_Feeling:

  1. 过这道题用了5h+,QAQ,tcl,真的醉了,还好今天休息,不然我要疯了,还要哭了QAQ,这道题可是排位赛的时候有人半小时过了的,我做了那么久,tcl,我tcl
  2. 最开始的时候敲的是SPFA,后来交了之后CE?????什么情况??????开始的时候多敲了一部分并查集,因为开始题意搞错了,所以用了并查集,后来又读了一遍发现理解错了,用不到,但是没删就交了,于是CE?????我把它删了之后就没有CE了???跟这个有关系吗?它开始running了,然后T在了54组样例,当时还忘记了CF可以看错误样例。就先去吃了个饭,吃饭的时候还重新算了下时间复杂度,在范围内啊,但还是怕就卡了时间叭。然后知道用stack可以优化SPFA,于是试了一下,发现还是T在了54组。于是我就坚信它是卡了时间,于是我就又敲了一遍Dijkstra,然后20组就T了???????什么情况。然后又到处优化了点小地方之后还是一样的T在了20组。
  3. 然后!!就突然灵光闪现想起可以看错误样例,然后看了下第54组,发现【第一行400 1】【第二行1 400】,然后就开始调试,发现CLion报错,运行不了????是哪里的问题,找了半天没找出来,看了下数组也开够了,但是就是运行不了?????后来我就想(小心思不可取):把这组样例特判一下,本来是放在了处理完了G_edge[ ]的后面,然后发现还是不能跑,然后我又换在了那个for循环的前面然后交了,!竟然真的给过了……然后又开始debug,发现还是有的地方不能跑,出现了问题,CLion报错。到底是哪里???哎,好崩溃。后来的后来的后来,我发现我跑mp [ ][ ]的点跑错了,我(1,1)(2,2)这种点也跑了,所以数组溢出了QAQ,我的天呐!!!怪不得之前第一发CE了!QAQ……然后我就交了,然后SPFA就过了。
  4. 我的那个Dijkstra也是跟SPFA一样跑了(1,1)这种点,然后改了这里之后发现还是不能跑,????调试的时候发现T_head[ ],莫名其妙出现了G_head[ ]里面的值,开始的时候没有,到后来的时候就有了,为什么???又是后来的后来,我发现QAQ我的G_edge[ ]数组少开了一倍,我哭!!!啊啊啊,然后改了之后果然也过了
  5. 其实我的经历远不止这些,五个小时啊!QAQ,反正就各种错误叭。tcl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值