poj 3463 Sightseeing (dij 求最短路和次短路并计数)

dijkstra求最短路和次短路的求法和计算  模板

dijkstra求最短路的变形。

外循环要循环2*n-1次,因为dis[n][2]有2*n个状态,而dis[s][0]已经用过一次。

算法:

1、如果比最短路短就更新最短路和次短路。

2、如果和最短路相等,更新最短路的计数。

3、如果和次短路相等,更新次短路的方法数。

4、如果比次短路短,更新次短路。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define maxn 1010
#define maxm 10010

using namespace std;

const int INF = 9999999;

int s,f,n,m,cnt,ans,head[maxn];
struct node
{
    int to,val,next;
}edge[maxm*2];
int dis[maxn][2],c[maxn][2];  //c[i][0]表示到点i的最短路的方法数,c[i][1]表示到点i的次短路的方法数
bool vis[maxn][2];   //dis[i][0]表示到点i的最短路,dis[i][1]表示到点i的次短路

void add(int x,int y,int z)
{
    edge[cnt].to = y;
    edge[cnt].val = z;
    edge[cnt].next = head[x];
    head[x] = cnt++;
}

void dij()
{
    memset(c,0,sizeof(c));
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        dis[i][0] = INF;
        dis[i][1] = INF;
    }
    dis[s][0] = 0;
    c[s][0] = 1;
    for(int i=0;i<2*n-1;i++)
    {
        int tmp = INF,tx = -1,flag;
        for(int j=1;j<=n;j++)  //找新的最短路和次短路
        {
            if(!vis[j][0] && dis[j][0]<tmp)
            {
                tmp = dis[j][0];
                tx = j;
                flag = 0;
            }
            else if(!vis[j][1] && dis[j][1]<tmp)
            {
                tmp = dis[j][1];
                tx = j;
                flag = 1;
            }
        }
        if(tx == -1) break;   //如果新的最短路和次短路都不存在 退出循环
        vis[tx][flag] = true;
        for(int j=head[tx];j!=-1;j=edge[j].next)  //更新和tx相连的边
        {
            int op = edge[j].to,w = edge[j].val;
            if(tmp+w<dis[op][0])  //比最短路短,更新最短路和次短路
            {
                dis[op][1]=dis[op][0];
                c[op][1] = c[op][0];
                dis[op][0] = tmp+w;
                c[op][0] = c[tx][flag];
            }
            else if(tmp+w==dis[op][0])  //等于最短路,更新最短路计数
                c[op][0]+=c[tx][flag];
            else if(tmp+w==dis[op][1])  //等于次短路,更新次短路计数
                c[op][1]+=c[tx][flag];
            else if(tmp+w<dis[op][1])   //小于次短路,更新最短路
            {
                dis[op][1] = tmp+w;
                c[op][1] = c[tx][flag];
            }
        }
    }
    if(dis[f][1]==dis[f][0]+1)
        c[f][0]+=c[f][1];
    printf("%d\n",c[f][0]);
}

int main()
{
    int T,a,b,c;
    scanf("%d",&T);
    while(T--)
    {
        memset(head,-1,sizeof(head));
        cnt = 0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
        }
        scanf("%d%d",&s,&f);
        dij();
    }
    return 0;
}

poj 3463 Sightseeing (dij 求最短路和次短路并计数)

时间: 2024-10-08 07:40:08

poj 3463 Sightseeing (dij 求最短路和次短路并计数)的相关文章

poj 3463 Sightseeing(最短路+次短路)

http://poj.org/problem?id=3463 大致题意:给出一个有向图,从起点到终点求出最短路和次短路的条数之和. 解法: 用到的数组:dis[i][0]:i到起点的最短路,dis[i][1]:i到起点的严格次短路 vis[i][0],vis[i][1]:同一维的vis数组,标记距离是否已确定 sum[i][0]:i到起点的最短路条数,sum[i][1]:i到起点的次短路条数 同一维dijkstra,内循环先找出最短的距离(次短路或最短路)d,然后枚举与该点相连的点: if(d

poj 3463 Sightseeing——次短路计数

题目:http://poj.org/problem?id=3463 当然要给一个点记最短路和次短路的长度和方案. 但往优先队列里放的结构体和vis竟然也要区分0/1,就像把一个点拆成两个点了一样. 不要区分k的fx. #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=1005,M=10005; int T

poj 3463 Sightseeing(次短路+条数统计)

/* 对dij的再一次理解 每个点依旧永久标记 只不过这里多搞一维 0 1 表示最短路还是次短路 然后更新次数相当于原来的两倍 更新的时候搞一下就好了 */ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> #define maxn 1010 using namespace std; int T,n,m,num,head[m

(最短路深入)POJ 3463 - Sightseeing

题意: 给一个有向图,计算最短路和比最短路少1的路的条数的和. 分析: 这题真的写死我了. 因为之前很少接触最短路问题,所谓偶尔遇到一次也是套的模板,根本没有细细思考过dijsktra算法.所以栽在了这题上. 这题就是求最短路和次短路. 核心思想在于修改最短路松弛的条件,并且每个节点同时维护最短路和次短路. 很多博主写的很详细,我也不多说了,只是写个博文记录一下自己有多渣,在学习算法的道路上自己真的思考的不够多,也不够努力. 代码: 1 #include <set> 2 #include &l

POJ 3463 Sightseeing (最短路 次短路)

Tour operator Your Personal Holiday organises guided bus trips across the Benelux. Every day the bus moves from one city S to another city F. On this way, the tourists in the bus can see the sights alongside the route travelled. Moreover, the bus mak

poj 3463 Sightseeing 最短路径数量

题意: 求有向图中最短路和比最短路大1的路径数量. 思路: 需要理解dijkstra算法中dis[n]数组的含义,设cnt[i]表示到点i的最短路径数量,cnt1[i]表示到点i比最短路大1的路径数量.在运行dijkstra算法的过程中每次获得最小dis[i]的时候可以对所有dis[v]+w(v,i)==dis[i]的v做如下更新cnt[i]+=cnt[v],cnt1[i]+=cnt1[v].而当所有值为某数的dis[i]计算完成时也就是对任意i,dis[i]为同一值且不再变化时,可以对这些满足

POJ 3463 - Sightseeing

题意:告诉你那n个点以及m条单向边.询问你从s点到e点最短路和比最短路长度大一的路一共有多少条. 思路:dijkstra变形.分别从起点和终点求一边dijkstra.用cnt数组分别记录从起点到达第i个点且长度为最短长度的路径数以及从原点到达第i个点且长度为最短长度的路径数._cnt数组记录到第i个节点的距离为最短距离+1的路径数.注意_cnt[i]所记录的路径只包括第i个节点的pre节点为最短路而pre节点到第i个节点不是最短路的情况.这样可以防止重复计算. 具体的松弛操作:设u为未经过的节点

poj3463 Sightseeing --- dij最短路和次短路

最短路好题啊. 题目给定起点和终点,要求最短路和次短路(要求次短路只比最短路大1)的道路数量. 重点在于次短路如何处理是最高效的呢 这就要求对dij算法路径更新的理解了. 我们用一个数组记录最短路,一个数组记录次短路. 每次对当前最短边,先更新最短路,更新不了最短路再更新次短路. 每条边处理两次,这样就可以在2n×n的复杂度内求得最短路和次短路了. #include<cstdio> #include<cstring> #include<queue> #include&l

poj 2449 Remmarguts&#39; Date 求第k短路 Astar算法

=.=好菜 #include <iostream> #include <cstdio> #include <string.h> #include <cstring> #include <queue> using namespace std; const int N = 1e3+10; const int M = 100000+10; typedef long long ll; const ll INF = 1e15; int n,m,head[N