POJ 3463 Sightseeing

最短路和次短路的结合,之前没有碰到过次短路。为此自己特地把最短路知识又复习了一遍,然后看了其他人的想法,最后才写了出来,具体来说,其实不太难,重点是理解思想。存储的时候采用邻接表。

解法:

用到的数组:dist[i][0]:i到起点的最短路,dist[i][1]:i到起点的严格次短路

visited[i][0],visited[i][1]:同一维的visited数组,标记距离是否已确定

sum[i][0]:i到起点的最短路条数,sum[i][1]:i到起点的次短路条数


同一维dijkstra,内循环先找出最短的距离(次短路或最短路)d,然后枚举与该点相连的点:

if(d < 最小)  更新最小和次小,包括距离以及路径条数

else if(d == 最小) 更新最短路径条数

else if(d < 次小) 更新次小,包括次小距离路径条数

else if(d == 次小) 更新次小路径条数


从这题自己也学到了一点东西:

之前写最短路的题目时,总是在求最短路的距离,没有碰到求最短路有几条的。那么只有把这题稍微修改一下不就可以求解最短路径有几条了吗?而且再把这题的算法稍微修改一下不就可以求次短路了吗?

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
const int inf=1<<28;
const int N=1005;
const int M=10005;
int dist[N][2],sum[N][2],head[N];
bool visited[N][2];
struct Edge
{
    int v,w;
    int next;
}edge[M];
int top,s,e,n,m;
void add_edge(int u,int v,int w)
{
    edge[top].v=v,edge[top].w=w;
    edge[top].next=head[u];
    head[u]=top++;
}
void solve()
{
    memset(visited,false,sizeof(visited));
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++)
    {
        dist[i][0]=inf;
        dist[i][1]=inf;
    }
    dist[s][0]=0;
    sum[s][0]=1;
    while(true)
    {
        int _min=inf,flag=-1,pos=-1;
        for(int i=1;i<=n;i++)
        {
            if(!visited[i][0]&&_min>dist[i][0])
                _min=dist[i][0],pos=i,flag=0;
            else if(!visited[i][1]&&_min>dist[i][1])
                _min=dist[i][1],pos=i,flag=1;
        }
        if(pos==-1)
            break;
        visited[pos][flag]=true;
        for(int i=head[pos];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v,w=edge[i].w;
            int temp=dist[pos][flag]+w;
            if(temp<dist[v][0])
            {
                dist[v][1]=dist[v][0];
                sum[v][1]=sum[v][0];
                dist[v][0]=temp;
                sum[v][0]=sum[pos][flag];
            }
            else if(temp==dist[v][0])
                sum[v][0]+=sum[pos][flag];
            else if(temp<dist[v][1])
            {
                dist[v][1]=temp;
                sum[v][1]=sum[pos][flag];
            }
            else if(temp==dist[v][1])
                sum[v][1]+=sum[pos][flag];
        }
    }
    if(dist[e][1]==dist[e][0]+1)
        sum[e][0]+=sum[e][1];
    printf("%d\n",sum[e][0]);
}
int main()
{
    int t,a,b,c;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        top=1;
        fill(head,head+N,-1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
        }
        scanf("%d%d",&s,&e);
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值