码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 3463 - Sightseeing

时间:2015-09-01 21:23:18      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:

题意:告诉你那n个点以及m条单向边。询问你从s点到e点最短路和比最短路长度大一的路一共有多少条。

思路:dijkstra变形。分别从起点和终点求一边dijkstra。用cnt数组分别记录从起点到达第i个点且长度为最短长度的路径数以及从原点到达第i个点且长度为最短长度的路径数。_cnt数组记录到第i个节点的距离为最短距离+1的路径数。注意_cnt[i]所记录的路径只包括第i个节点的pre节点为最短路而pre节点到第i个节点不是最短路的情况。这样可以防止重复计算。

具体的松弛操作:设u为未经过的节点中距离原点最近的点,那么枚举u的每一条边,如果dist[flag][u]+e.w==dist[flag][e.v]

那么到达v点且为最短路的路径数cnt[v]+=cnt[u]。如果dist[u]+e.w==dist[e.v]+1,那么到达v点且长度为最短路+1的路径数_cnt[v]+=cnt[u]。如果如果dist[u]+e.w<dist[e.v],先判断dist[flag][u]+e.w等不等于dist[e.v]+1,如果等于,那么原来的最短路路径数就变成了最短路长度加1的路径数_cnt[v]=cnt[v],如果不等于,那么最短路长度加1的路径数就为0。接着更新dist[v]并且让cnt[v]=cnt[u]。接着在dijkstra求出从终点到第i个点的最短路径数就好了,这一次dijkstra不需要再求最短路径+1的条数了。

然后最终的答案就等于cnt[e]再加上从起点到第i个点长度为最短路长度+1乘上终点到第i个点的最短路的路径数。

技术分享
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAXM=11000;
const int MAXN=1100;
struct Edge{
    int v,w,nex;
}edge[2][MAXM];
int head[2][MAXN];
bool vis[MAXN];
int dist[2][MAXN];
int tot1,tot2,n,m,s,e,u,v,w;
int cnt[2][MAXN];
int _cnt[MAXN];
void addedge(int u,int v,int w)
{
    edge[0][tot1].v=v;
    edge[0][tot1].w=w;
    edge[0][tot1].nex=head[0][u];
    head[0][u]=tot1++;

    edge[1][tot2].v=u;
    edge[1][tot2].w=w;
    edge[1][tot2].nex=head[1][v];
    head[1][v]=tot2++;
}

void dijkstra(int flag)
{
    int ss=flag?e:s;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
        dist[flag][i]=INF;
    cnt[flag][ss]=1;
    dist[flag][ss]=0;
    while(1)
    {
        int u=-1;
        for(int v=1;v<=n;v++)
            if(!vis[v]&&(u==-1||dist[flag][v]<dist[flag][u]))
                u=v;
        if(u==-1)
            break;
        vis[u]=true;
        for(int i=head[flag][u];i!=-1;i=edge[flag][i].nex)
        {
            Edge e=edge[flag][i];
            if(dist[flag][u]+e.w==dist[flag][e.v])
                cnt[flag][e.v]+=cnt[flag][u];
            if(dist[flag][u]+e.w==dist[flag][e.v]+1&&!flag)
                _cnt[e.v]+=cnt[flag][u];
            if(dist[flag][u]+e.w<dist[flag][e.v])
            {
                if(!flag)
                {
                    if(dist[flag][u]+e.w+1==dist[flag][e.v])
                        _cnt[e.v]=cnt[flag][e.v];
                    else
                        _cnt[e.v]=0;
                }
                dist[flag][e.v]=dist[flag][u]+e.w;
                cnt[flag][e.v]=cnt[flag][u];
            }
        }
    }
}

void init()
{
    tot1=tot2=0;
    memset(head,-1,sizeof(head));
    memset(cnt,0,sizeof(cnt));
    memset(_cnt,0,sizeof(cnt));
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
        }
        scanf("%d%d",&s,&e);
        dijkstra(0);
        dijkstra(1);
        int ans=cnt[0][e];
        //printf("%d\n",ans);
        //for(int i=1;i<=n;i++)
            //printf("%d %d\n",_cnt[i],cnt[1][i]);
        for(int i=1;i<=n;i++)
            if(dist[0][i]+dist[1][i]==dist[0][e])
                ans+=_cnt[i]*cnt[1][i];
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

POJ 3463 - Sightseeing

标签:

原文地址:http://www.cnblogs.com/onlyAzha/p/4776886.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!