题目大意:给出一个单向带权图和一个点s,求点u,u到s的最短路径和s到u的最短路径之和最大。
对于s到任意点的最短路,直接dijkstra可以求出。
对于任意点到s的最短路,如果将所有边反向然后求一次最短路,容易证明,求出的s到任意点v的最短路s-->v就是原来没有反向的图的v-->s的最短路。
所以先求一次dijkstra,保存此次的结果,然后把所有的边反向,权值不变,再求一次dijkstra,将两次结果加起来,计算它们之中的最大值。
#include<stdio.h> #include<stdlib.h> #include<vector> #include<queue> using namespace std; const int maxn=1010; const int INF=(1<<29); struct edge { int to; int dis; }; struct edge2 { int from; int to; int dis; }; struct heapnode { int di; int num; bool operator< (const heapnode j) const { return di>j.di; } }; edge2 e[100010]; int d[maxn]; int sum[maxn]; int use[maxn]; int n; vector<edge> G[maxn]; void dijkstra(int s); int main(void) { int i,u,v,p,q,m,ans; edge ed; while(scanf("%d%d%d",&n,&m,&q)==3) { for(i=1;i<=n;i++) { G[i].clear(); } for(i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&p); ed.to=v; ed.dis=p; G[u].push_back(ed); e[i].from=u; e[i].to=v; e[i].dis=p; } dijkstra(q); for(i=1;i<=n;i++) { sum[i]=d[i]; G[i].clear(); } for(i=1;i<=m;i++) { ed.to=e[i].from; ed.dis=e[i].dis; G[e[i].to].push_back(ed); } dijkstra(q); ans=0; for(i=1;i<=n;i++) { ans=d[i]+sum[i]>ans?d[i]+sum[i]:ans; } printf("%d\n",ans); } return 0; } void dijkstra(int s) { int i,u,p; heapnode h; priority_queue<heapnode> heap; for(i=1;i<=n;i++) { d[i]=INF; use[i]=0; } h.di=0; h.num=s; d[s]=0; heap.push(h); while(heap.empty()==false) { h=heap.top(); heap.pop(); u=h.num; if(use[u]==0) { use[u]=1; p=G[u].size(); for(i=0;i<p;i++) { if(d[u]+G[u][i].dis<d[G[u][i].to]) { d[G[u][i].to]=d[u]+G[u][i].dis; h.di=d[G[u][i].to]; h.num=G[u][i].to; heap.push(h); } } } } }
时间: 2024-12-13 16:00:15