题意:求最短路和比最短路长度多1的次短路的个数
本来想图(有)方(模)便(版)用spfa的,结果妹纸要我看看dijkstra怎么解....
写了三遍orz
Ver1.0:堆优化+邻接表,WA
1 //不能用堆优化+邻接表,因为需要处理dis[i][0]和dis[i][1]两套,如果都挤到一个堆里就乱套了 2 3 #include <iostream> 4 #include <cstdio> 5 #include <queue> 6 #include <cstring> 7 #include <vector> 8 using namespace std; 9 const int Ni = 10000; 10 const int INF = 1<<27; 11 struct node 12 { //eg[i].x eg[i].d i:start x:end d:distance 13 int x,d; 14 node(){} 15 node(int a,int b){x=a;d=b;} 16 bool operator < (const node & a) const //用于优先队列, 取距离原点最近的点 17 { 18 if(d==a.d) return x<a.x; 19 else return d > a.d; 20 } 21 }; 22 vector<node> eg[Ni]; 23 int dis[Ni][5],cnt[Ni][5],n,T; 24 25 void Dijkstra(int s) //1.比最短路短2.等于最短路3.长于最短路但短于次短路4.等于次短路 26 { 27 memset(dis,0,sizeof(dis)); 28 memset(cnt,0,sizeof(cnt)); 29 30 int i; 31 for(i=0;i<=n;i++) 32 { 33 dis[i][1]=INF; 34 dis[i][2]=INF; 35 } 36 dis[s][1]=0; 37 dis[s][2]=0; 38 priority_queue<node> q; //q:优先队列,用来取离原点最近的顶点 39 q.push(node(s,dis[s][1])); //初始只有一个原点自己 40 while(!q.empty()) 41 { 42 node x=q.top();q.pop(); 43 for(i=0;i<eg[x.x].size();i++) 44 { 45 node y=eg[x.x][i]; 46 if(dis[y.x][1]>x.d+y.d) //1 47 { 48 cnt[y.x][1]=1; 49 cnt[y.x][2]=1; 50 dis[y.x][2]=dis[y.x][1]; 51 dis[y.x][1]=x.d+y.d; 52 q.push(node(y.x,dis[y.x][1])); 53 } 54 else if (dis[y.x][1]==x.d+y.d) //2 55 { 56 cnt[y.x][1]++; 57 } 58 else if ((dis[y.x][1]<x.d+y.d)&&(x.d+y.d<dis[y.x][2])) //3 59 { 60 cnt[y.x][2]=1; 61 dis[y.x][2]=x.d+y.d; 62 } 63 else if (x.d+y.d==dis[y.x][2]) //4 64 { 65 cnt[y.x][2]++; 66 } 67 } 68 } 69 } 70 71 void debug() 72 { 73 cout<<"Debug only"<<endl; 74 for (int i=1;i<=n;i++) 75 printf("%d - %d %d - %d %d ",i,dis[i][1],cnt[i][1],dis[i][2],cnt[i][2]); 76 cout<<ans1<<" "<<ans2<<endl; 77 78 } 79 80 int main() 81 { 82 scanf("%d",&T); 83 while (T--) 84 { 85 int a,b,d,m,k,st; 86 scanf("%d%d",&n,&m); 87 for(int i=0;i<=n;i++) eg[i].clear(); 88 while(m--) 89 { 90 scanf("%d%d%d",&a,&b,&d); 91 eg[a].push_back(node(b,d)); 92 } 93 scanf("%d %d",&k,&st); 94 Dijkstra(k); 95 96 debug1(); 97 98 int t1=dis[st][1],t2=dis[st][2],ans1=cnt[st][1],ans2; 99 if (t2-t1==1) 100 ans2=cnt[st][2]; 101 else ans2=0; 102 printf("%d ",ans1+ans2); 103 } 104 105 return 0; 106 }
Ver2.0:邻接矩阵,WA
1 //不能用邻接矩阵,因为会有重边 2 3 #include <iostream> 4 #include <cstring> 5 using namespace std; 6 #define MAXINT 9999999 7 8 int minx,minj,x,y,t,k,n,m,tmp,st,flag; 9 int v[1010][3],d[1010][3],cnt[1010][3],a[1010][1010]; 10 11 int main() 12 { 13 int T; 14 cin>>T; 15 while (T--) 16 { 17 cin>>n>>m; 18 memset(a,0,sizeof(a)); 19 memset(d,MAXINT,sizeof(d)); 20 memset(v,0,sizeof(v)); 21 memset(cnt,0,sizeof(cnt)); 22 23 for (int i=1;i<=m;i++) 24 { 25 cin>>x>>y>>t; 26 a[x][y]=t; 27 } 28 cin>>k>>st; 29 d[k][1]=0; //d[k][2]=0; 30 cnt[k][1]=1; // cnt[k][2]=1; 31 32 for (int i=1;i<=2*n;i++) 33 { 34 minx=MAXINT; 35 for (int j=1;j<=n;j++) 36 { 37 if ((v[j][1]==0)&&(d[j][1]<minx)) 38 { 39 minx=d[j][1]; 40 minj=j; 41 flag=1; 42 } 43 if ((v[j][2]==0)&&(d[j][2]<minx)) 44 { 45 minx=d[j][2]; 46 minj=j; 47 flag=2; 48 } 49 } 50 v[minj][flag]=1; 51 for (int j=1;j<=n;j++) 52 // if ((v[j][1]==0)&&(a[minj][j]>0)) 53 if (a[minj][j]>0) 54 { 55 tmp=minx+a[minj][j]; 56 57 if (tmp<d[j][1]) 58 { 59 d[j][2]=d[j][1]; 60 d[j][1]=tmp; 61 cnt[j][2]=cnt[j][1]; 62 cnt[j][1]=cnt[minj][flag]; 63 } 64 else if (tmp==d[j][1]) 65 { 66 cnt[j][1]+=cnt[minj][flag]; 67 } 68 else if (tmp<d[j][2]) 69 { 70 d[j][2]=tmp; 71 cnt[j][2]=cnt[minj][flag]; 72 } 73 else if (tmp==d[j][2]) 74 { 75 cnt[j][2]+=cnt[minj][flag]; 76 } 77 } 78 } 79 80 for (int i=1;i<=n;i++) 81 cout<<d[i][1]<<" "<<cnt[i][1]<<" = "<<d[i][2]<<" "<<cnt[i][2]<<endl; 82 cout<<endl; 83 int t1=d[st][1],t2=d[st][2],ans1=cnt[st][1],ans2; 84 if (t2==t1+1) ans2=cnt[st][2]; else ans2=0; 85 cout<<ans1+ans2<<endl; 86 } 87 return 0; 88 }
Ver3.0:朴素n^2算法+邻接表 AC
1 #include <stdio.h> 2 #include <string.h> 3 #define INF 999999 4 5 struct node 6 { 7 int to,dat; 8 }edge[1010][1010]; 9 10 int cnt[1010][2],d[1010][2],vis[1010][2]; 11 int x,y,z,n,m,T,st,ed; 12 13 void insert_node(int x,int y,int z) 14 { 15 edge[x][0].dat++; 16 int tmp=edge[x][0].dat; 17 edge[x][tmp].to=y; 18 edge[x][tmp].dat=z; 19 } 20 21 void dijkstra() 22 { 23 memset(vis,0,sizeof(vis)); 24 memset(d,INF,sizeof(d)); 25 memset(cnt,0,sizeof(cnt)); 26 d[st][0]=0; 27 cnt[st][0]=1; 28 29 for (int i=1;i<=2*n;i++) 30 { 31 int minj,flag,minx=INF; 32 for (int j=1;j<=n;j++) 33 if ((vis[j][0]==0)&&(d[j][0]<minx)) 34 { 35 minx=d[j][0]; 36 minj=j; 37 flag=0; 38 } 39 else if ((vis[j][1]==0)&&(d[j][1]<minx)) 40 { 41 minx=d[j][1]; 42 minj=j; 43 flag=1; 44 } 45 vis[minj][flag]=1; 46 int tmp=edge[minj][0].dat; 47 for (int j=1;j<=tmp;j++) 48 { 49 int yy=edge[minj][j].to; 50 int zz=edge[minj][j].dat; 51 //if (vis[yy][flag]==0) 52 //{ 53 int tm=minx+zz; 54 if (tm<d[yy][0]) 55 { 56 d[yy][1]=d[yy][0]; 57 cnt[yy][1]=cnt[yy][0]; 58 d[yy][0]=tm; 59 cnt[yy][0]=cnt[minj][flag]; 60 } 61 else if (tm==d[yy][0]) 62 { 63 cnt[yy][0]+=cnt[minj][flag]; 64 } 65 else if (tm<d[yy][1]) 66 { 67 d[yy][1]=tm; 68 cnt[yy][1]=cnt[minj][flag]; 69 } 70 else if (tm==d[yy][1]) 71 { 72 cnt[yy][1]+=cnt[minj][flag]; 73 } 74 //} 75 76 } 77 78 } 79 } 80 81 int main() 82 { 83 // freopen("in.txt","r",stdin); 84 85 scanf("%d",&T); 86 while (T--) 87 { 88 memset(edge,0,sizeof(edge)); 89 scanf("%d %d",&n,&m); 90 for (int i=1;i<=m;i++) 91 { 92 scanf("%d %d %d",&x,&y,&z); 93 insert_node(x,y,z); 94 } 95 scanf("%d %d",&st,&ed); 96 97 /* 98 for (int i=1;i<=n;i++) 99 for (int j=1;j<=edge[i][0].dat;j++) 100 printf("Debug: %d -> %d = %d ",i,edge[i][j].to,edge[i][j].dat); 101 */ 102 103 dijkstra(); 104 105 int tx,ty,ans2,ans1; 106 tx=d[ed][0]; ty=d[ed][1]; 107 ans1=cnt[ed][0]; 108 if (ty-tx==1) ans2=cnt[ed][1]; 109 else ans2=0; 110 // printf("%Debug: %d %d %d %d ",tx,ty,ans1,ans2); 111 printf("%d ",ans1+ans2); 112 } 113 return 0; 114 }
邻接表很少用到都不大会写了>_<
dij松弛的条件改变下,有四种情况
1.比最短路短2.等于最短路3.长与最短路但短于次短路4.等于次短路
d[i][0]记最短路, d[i][1]记次短路
注意这里:
int tm=minx+zz; if (tm<d[yy][0]) { d[yy][1]=d[yy][0]; cnt[yy][1]=cnt[yy][0]; d[yy][0]=tm; cnt[yy][0]=cnt[minj][flag]; } else if (tm==d[yy][0]) { cnt[yy][0]+=cnt[minj][flag]; //因为松弛操作是从minj点开始的 //(d[minj]+a[minj,j]<d[j]) //所以记录cnt的时候要+=cnt[minj][flag] //一开始以为直接+1就行,WA了 //前面的cnt[yy][0]=cnt[minj][flag]同理 } else if (tm<d[yy][1]) { d[yy][1]=tm; cnt[yy][1]=cnt[minj][flag]; } else if (tm==d[yy][1]) { cnt[yy][1]+=cnt[minj][flag]; }
Reference:
http://blog.csdn.net/wmn_wmn/article/details/7376707
http://www.cnblogs.com/Missa/archive/2012/08/31/2665244.html