POJ 3463 Sightseeing

POJ 3463 Sightseeing

题目大意:旅行团每天固定的从S地出发到达T地,为了省油要求尽量走最短路径或比最短路径长1单位距离的路径,求满足条件的路径条数

分析:根据描述可知,本题的要求就是要求出最短路和比最短路长1的次短路,因此可用Dijkstra来解决。具体做法如下:用两组数分别记录最短路和次短路的长度(dist),条数(cnt),访问标记(used),建一个优先队列,元素单位包括节点序号(v),该节点路经长(len),以及记录路径类型(ref),每次从优先队列中取出有效节点后,用它所记录的路径长更新待比较路径,分别用它和当前所记录的该节点的最短路径以及此段路径比较,满足更新条件则记录路径类型,并生成新节点加入优先队列,同时更新当前节点处该类型路径条数。如果不满足条件但是满足相等关系,则添加相应的条数到该节点所记录的路径条数上。

代码及其思想借鉴了此处:http://www.cnblogs.com/zhangjinglei/archive/2009/07/31/1536160.html

#include<stdio.h>

#include<memory.h>

#include<queue>

using namespace std;

#define N 1001

#define M 10001

#define INF 0x7fffffff

#define clear(a) memset(a,0,sizeof(a))

struct Edge

{

    int v;

    int len;

    int ref;

    Edge *link;

    Edge new_E(int v1,int l,int r){v=v1,len=l,ref=r;return *this;}

}*E[N],mempool[M];

int dist[N][2],used[N][2],cnt[N][2];

int n,m,memh,S,T;

void AddEdge(int u,int v,int len)

{

    Edge *e=&mempool[memh++];

    e->v=v;

    e->len=len;

    e->link=E[u];

    E[u]=e;

}

bool operator <(Edge a,Edge b)

{

    return a.len>b.len;

}

priority_queue<Edge,vector<Edge> >Q;

void InitData()

{

    int i,u,v,len;

    memh=0;

    scanf("%d%d",&n,&m);

    clear(E);

    for(i=1;i<=m;i++){

        scanf("%d%d%d",&u,&v,&len);

        AddEdge(u,v,len);

    }

    scanf("%d%d",&S,&T);

}

int Dijstra()

{

    Edge D,P;

    clear(cnt);

    clear(used);

    for(int i=1;i<=n;i++)

        dist[i][0]=dist[i][1]=INF;

    dist[S][0]=0;

    cnt[S][0]=1;

    while(!Q.empty())   Q.pop();

    Q.push(D.new_E(S,0,0));

    while(!Q.empty()){

        P=Q.top();

        Q.pop();

        if(!used[P.v][P.ref]){

            used[P.v][P.ref]=1;

            for(Edge *e=E[P.v];e;e=e->link){

                int tmp=P.len+e->len;

                if(tmp<dist[e->v][0]){

                    if(dist[e->v][0]!=INF){

                        dist[e->v][1]=dist[e->v][0];

                        cnt[e->v][1]=cnt[e->v][0];

                        Q.push(D.new_E(e->v,dist[e->v][0],1));

                    }

                    dist[e->v][0]=tmp;

                    cnt[e->v][0]=cnt[P.v][P.ref];

                    Q.push(D.new_E(e->v,tmp,0));

                }

                else if(tmp==dist[e->v][0]){

                    cnt[e->v][0]+=cnt[P.v][P.ref];

                }

                else if(tmp<dist[e->v][1]){

                    dist[e->v][1]=tmp;

                    cnt[e->v][1]=cnt[P.v][P.ref];

                    Q.push(D.new_E(e->v,tmp,1));

                }

                else if(dist[e->v][1]==tmp){

                    cnt[e->v][1]+=cnt[P.v][P.ref];

                }

            }

        }

    }

    if(dist[T][1]-1==dist[T][0])

        cnt[T][0]+=cnt[T][1];

    return cnt[T][0];

}

int main()

{

    int cs;

    freopen("data.txt","r",stdin);

    for(scanf("%d",&cs);cs;cs--){

        InitData();

        printf("%d/n",Dijstra());

    }

    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值