几天没有做题了。想好好的整合一下知识。不然的话真的采用题海战术这样绝对是不明智的!
鄙人目前对图论,组合数学,计算几何感兴趣。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;
}