【题目大意】
给出邻接矩阵以及到达各个点需要付出的代价(起点和终点没有代价),求出从给定起点到终点的最短路,并输出字典序最小的方案。
【思路】
在堆优化Dijkstra中,用pre记录前驱。如果新方案和旧方案相等,比较两个方案的字典序。
【坑点】
我先求出了最短路(包括终点要付出代价),输出的时候再减去终点的代价。
有可能会给出S==T的情况……在这种情况下,最短路就是0,减去代价要变成负数了QAQ所以要特判一下。坑了好几个小时orz
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<queue> 8 #include<vector> 9 using namespace std; 10 const int MAXN=2000+50; 11 const int INF=0x7fffffff; 12 13 struct edge 14 { 15 int to,len; 16 }; 17 18 vector<edge> E[MAXN]; 19 priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > pque; 20 int vis[MAXN],dis[MAXN],pre[MAXN],tax[MAXN]; 21 int s1[MAXN],s2[MAXN],n; 22 23 void addedge(int u,int v,int w) 24 { 25 E[u].push_back((edge){v,w}); 26 } 27 28 void init() 29 { 30 for (int i=1;i<MAXN;i++) vector<edge>().swap(E[i]); 31 while (!pque.empty()) pque.pop(); 32 for (int i=1;i<=n;i++) 33 for (int j=1;j<=n;j++) 34 { 35 int aij; 36 scanf("%d",&aij); 37 if (aij>=0 && i!=j) addedge(i,j,aij); 38 } 39 for (int i=1;i<=n;i++) scanf("%d",&tax[i]); 40 } 41 42 int compare(int now,int before) 43 { 44 memset(s1,0,sizeof(s1)); 45 memset(s2,0,sizeof(s2)); 46 int i=0,j=-1; 47 s1[0]=before; 48 while (now!=0) s1[++i]=now,now=pre[now]; 49 while (before!=0) s2[++j]=before,before=pre[before]; 50 for (;i>=0 && j>=0;i--,j--) 51 if (s1[i]<s2[j]) return 1; 52 else if (s1[i]>s2[j]) return 0; 53 return (s1<s2); 54 } 55 56 int dijkstra(int S,int T) 57 { 58 for (int i=1;i<=n;i++) vis[i]=0,dis[i]=INF,pre[i]=-1; 59 dis[S]=0,pre[S]=0; 60 pque.push(pair<int,int>(0,S)); 61 while (!pque.empty()) 62 { 63 int u=pque.top().second;pque.pop(); 64 vis[u]=1; 65 for (int i=0;i<E[u].size();i++) 66 { 67 int v=E[u][i].to,len=E[u][i].len+tax[v]; 68 if (dis[v]>=dis[u]+len) 69 { 70 if (dis[v]>dis[u]+len) 71 { 72 dis[v]=dis[u]+len; 73 pre[v]=u; 74 pque.push(pair<int,int>(dis[v],v)); 75 } 76 else if (dis[v]==dis[u]+len && compare(u,v)) 77 { 78 pre[v]=u; 79 pque.push(pair<int,int>(dis[v],v)); 80 } 81 } 82 } 83 } 84 85 int i=0,now=T; 86 while (now!=0) s1[++i]=now,now=pre[now]; 87 printf("From %d to %d : ",S,T); 88 printf("Path: "); 89 while (i>=1) 90 { 91 printf("%d",s1[i--]); 92 if (i!=0) printf("-->"); 93 } 94 printf(" Total cost : %d ",(S==T)?0:dis[T]-tax[T]); 95 //注意如果S==T的时候,就不要减去tax了,否则会出现负值。 96 } 97 98 void solve() 99 { 100 int a,b; 101 while (scanf("%d%d",&a,&b)) 102 { 103 if (a==-1 && a==b) return; 104 dijkstra(a,b); 105 } 106 } 107 108 int main() 109 { 110 while (scanf("%d",&n)) 111 { 112 if (n==0) break; 113 init(); 114 solve(); 115 } 116 return 0; 117 }
附上随机数据生成:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 freopen("samplein.txt", "w", stdout); 7 srand((unsigned)time(NULL)); 8 int n=rand() % 100; 9 int ne; 10 cout<<n<<endl; 11 for (int i=0;i<n;i++) 12 { 13 for (int j=0;j<n;j++) 14 { 15 if (i==j) 16 { 17 printf("%d",0); 18 } 19 else 20 { 21 if((rand()%n)<(n/5)) 22 { 23 printf("-1"); 24 } 25 else 26 { 27 printf("%d",(rand()%(n-1)+1)); 28 } 29 } 30 printf(" "); 31 } 32 printf(" "); 33 34 } 35 36 for (int i=0;i<n;i++) 37 { 38 printf("%d ",(rand()%n)); 39 } 40 41 printf(" "); 42 int tmp=rand()%n; 43 for (int i=0;i<tmp;i++) 44 { 45 int temp1=(rand()%(n-1)+1); 46 int temp2=(rand()%(n-1)+1); 47 printf("%d %d ",temp1,temp2); 48 49 } 50 51 printf("%d %d ",-1,-1); 52 printf("%d ",0); 53 54 fclose(stdout); 55 return 0; 56 }