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