POJ 3464 最短路径与次短路径的条数

几天没有做题了。想好好的整合一下知识。不然的话真的采用题海战术这样绝对是不明智的!

鄙人目前对图论,组合数学,计算几何感兴趣。DP还好~

做题做了一道次短路径的题。以前也想过这样的解法并且也还码过代码,很明显的WA了。

这次借鉴了网上的做法,并个人做了认真的思考。看来我对Dij的算法理解还是不是很深啊!虽然通过YY,想出了最短路径条数的计算方法,次短路径却怎么也解决不了。

研究过大神的算法后,好不容易总算是理解了。

这样对于图,开两个维度的cnt,vis,dis分别计算路径的条数,是否访问,单源点距离。首先对dis数组进行遍历,找到两个维度中的最小值。同时对提供该最小值的响应维度顶点采取拜访过标记。这样用Dij去更新数组的时候就可以更新不同的维度了。另外呢这样会出现4种情况需要更新距离的:

在三角距离公式中dis[v]>min+w;

1.比最短路径维度的最短路径还要短:明显的最短路径要更新了,所以到该点的最短路径和条数在更新后就变成了次短路径了,这是明显的。所以对次短路径及条数进行存储,最短路径和条数进行更新。

2.和最短路径维度的最短路径相等:这样不要更新最短路,但是由上一个点到该点的路径增多了,所以将上一条路径的到达条数流到自己身上来。

3.比次短路径维度的最短路径要短:这时明显的比最短路径要长,所以对次短路径进行更新。同时到达路径数修改为上一点流过来的路径数。

4.和次短路径维度的最短路径相等:将到达路径的点流到自己身上。这样就好了。

这样总结一番后发现,嗯~ 很有道理啊!

图论 大爱啊~

#include<iostream>
#define MAXE 10005
#define MAXV 1005
using namespace std;

struct Node
{
       int v,len;
       Node *next;
}edge[MAXE],*ptr[MAXV];

int cnt[MAXE][2],dis[MAXE][2];
bool vis[MAXE][2];

int E,V,S,F;
void addEdge( int u,int v,int pri,int i )
{
     Node *p=&edge[i];
     p->v=v;
     p->len=pri;
     p->next=ptr[u];
     ptr[u]=p;
}

void Dijstra( int s )
{
     memset( cnt,0,sizeof(cnt) );
     memset( dis,0x7F,sizeof(dis) );
     memset( vis,0,sizeof(vis) );
     dis[s][0]=0;
     cnt[s][0]=1;
     int i,j,k,flag;
     for( i=1;i<=2*V;i++ )
     {
          int min=0x7F7F7F7F;
          k=-1;
          for( j=1;j<=V;j++ )
          {
               if( !vis[j][0] && min>dis[j][0] )
               {
                   min=dis[j][0];
                   k=j;
                   flag=0;
               }
               else if( !vis[j][1] && min>dis[j][1] )
               {
                    min=dis[j][1];
                    k=j;
                    flag=1;
               }
          }
          
          if( k==-1 ) break;
          vis[k][flag]=true;
          
          Node *p=ptr[k];
          
          while( p )
          {
                 if( dis[p->v][0]>min+p->len )//更新最短路径数组 
                 {
                     dis[p->v][1]=dis[p->v][0];
                     dis[p->v][0]=min+p->len;
                     cnt[p->v][1]=cnt[p->v][0];
                     cnt[p->v][0]=cnt[k][flag];
                 }
                 else if( dis[p->v][0]==min+p->len )
                 {
                      cnt[p->v][0]+=cnt[k][flag];
                 }
                 else if( dis[p->v][1]>min+p->len )
                 {
                      cnt[p->v][1]=cnt[k][flag];    
                      dis[p->v][1]=min+p->len;
                 }
                 else if( dis[p->v][1]==min+p->len )
                 {     
                       cnt[p->v][1]+=cnt[k][flag];
                 }
                 p=p->next;
          }
     }
     return ;
}

int main()
{
    int T;
    scanf( "%d",&T );
    while( T-- )
    {
           scanf( "%d %d",&V,&E );
           int i,j,u,v,p;
           for( i=0;i<MAXV;i++ ) ptr[i]=NULL;
           for( i=0;i<E;i++ )
           {
                scanf( "%d %d %d",&u,&v,&p );
                addEdge( u,v,p,i );
           }
           scanf( "%d %d",&S,&F );
           Dijstra(S);
           int ans=cnt[F][0];
           //printf( "%d %d\n",dis1[F],dis2[F] );
           if( dis[F][0]+1==dis[F][1] )
               ans+=cnt[F][1];
           printf( "%d\n",ans );
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值