1688 Sightseeing(最短路+次短路+计数)

题意:找出从S到F两个点之间的最短路和比最短路长1的次短路的条数之和。

分析:最短路很好求,关键是次短路,郁闷呀

不过,如果对最短路的更新距离的过程有更深的认识的话,就好办很多了。

用一个二维数组记录每一个节点距离起始点的最短距离和次短距离,再开一个二维数组记录路径数

更新状态时:

 1)新值小于最短路径长:更新最短路径长,计数;次短路径长,计数

2)新值等于最短路径长:更新最短路径计数

 3)新值大于最短路径长,小于次短路径长:更新次短路径长,计数

4)新值等于次短路径长:更新次短路径计数


#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
const int maxn=1005,inf=1<<29;
struct edge{int to,cost;};
struct node
{
    int s,dist,f;//顶点、顶点到起点距离、标记变量
    friend bool operator <(node a,node b)
    {
        if(a.dist!=b.dist) return a.dist>b.dist;
        return a.s>b.s;
    }
};
vector<edge>G[maxn];
int dp[maxn][3];//dp[i][1]计i点到起点最短路的数量,dp[i][2]计i点到起点次短路的数量
int d[maxn][3];//d[i][1]计i点到起点最短路的长度,d[i][2]计i点到起点次短路的长度
int vis[maxn][3];
int n,m,s,e;
void Dijkstra()
{
    memset(dp,0,sizeof(dp));
    memset(vis,0,sizeof(vis));
    fill(&d[0][0],&d[maxn][0],inf);
    priority_queue<node>q;
    node now,t;
    now.s=s;now.dist=0;now.f=1;
    d[s][1]=0;dp[s][1]=1;
    q.push(now);
    while(q.size())
    {
        now=q.top();q.pop();
        if(vis[now.s][now.f]) continue;
        vis[now.s][now.f]=1;
        for(int i=0;i<G[now.s].size();i++)
        {
            int v=G[now.s][i].to,w=G[now.s][i].cost;
            if(!vis[v][1]&&d[v][1]>now.dist+w)// 1)新值小于最短路径长:更新最短路径长,计数;次短路径长,计数
            {
                if(d[v][1]!=inf)
                {
                    t.s=v;t.f=2;t.dist=d[v][1];
                    d[v][2]=d[v][1];
                    dp[v][2]=dp[v][1];
                    q.push(t);
                }
                t.s=v;t.f=1;t.dist=now.dist+w;
                d[v][1]=t.dist;
                dp[v][1]=dp[now.s][now.f];
                q.push(t);
            }
            else if(!vis[v][1]&&d[v][1]==now.dist+w) dp[v][1]+=dp[now.s][now.f];//2)新值等于最短路径长:更新最短路径计数
            else if(!vis[v][2]&&d[v][2]>now.dist+w)// 3)新值大于最短路径长,小于次短路径长:更新次短路径长,计数
            {
                t.s=v;t.f=2;t.dist=now.dist+w;
                d[v][2]=t.dist;
                dp[v][2]=dp[now.s][now.f];
                q.push(t);
            }
            else if(!vis[v][2]&&d[v][2]==now.dist+w) dp[v][2]+=dp[now.s][now.f];//4)新值等于次短路径长:更新次短路径计数
        }
    }
}
int main()
{
    int Case;
    scanf("%d",&Case);
    while(Case--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++) G[i].clear();
        for(int i=0;i<m;i++)
        {
            edge t;
            int a,b,w;
            scanf("%d%d%d",&a,&b,&w);
            t.to=b;t.cost=w;
            G[a].push_back(t);
        }
        scanf("%d%d",&s,&e);
        Dijkstra();
        if(d[e][2]==d[e][1]+1) printf("%d\n",dp[e][2]+dp[e][1]);
        else printf("%d\n",dp[e][1]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值