题目:洛谷P2176。
题目大意:有n个点m条无向边,一个人要从1走到n,他会走最短路。现在可以让一条边的长度翻倍,求翻倍后这个人要多走多少距离。
解题思路:首先可以知道,翻倍肯定是在最短路上的某条边翻,否则他走的路不会变。我们先跑一遍最短路,记录下走的边,再枚举哪条边翻倍,然后跑最短路,记录下答案即可。
此题好像卡SPFA,于是我用堆优化Dijkstra秒杀。
时间复杂度$O(nm\log n)$。
C++ Code:
#include<cstdio> #include<cstring> #include<ext/pb_ds/priority_queue.hpp> using namespace __gnu_pbds; struct edge{ int from,to,dis,nxt; }e[10005]; struct heapnode{ int u,d; bool operator<(const heapnode& rhs)const{return d>rhs.d;} }; priority_queue<heapnode>q; int n,m,head[10005],cnt,d[10005],prev[10005],prea[10005]; inline void addedge(int from,int to,int dis){ e[++cnt]=(edge){from,to,dis,head[from]}; head[from]=cnt; e[++cnt]=(edge){to,from,dis,head[to]}; head[to]=cnt; } void dijkstra(){ memset(d,0x3f,sizeof d); memset(prev,0,sizeof prev); q.push((heapnode){1,d[1]=0}); while(!q.empty()){ heapnode x=q.top(); q.pop(); int u=x.u; if(d[u]!=x.d)continue; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(d[v]>d[u]+e[i].dis){ d[v]=d[u]+e[i].dis; prev[v]=i; q.push((heapnode){v,d[v]}); } } } } int main(){ cnt=1; scanf("%d%d",&n,&m); for(;m--;){ int x,y,z; scanf("%d%d%d",&x,&y,&z); addedge(x,y,z); } dijkstra(); memcpy(prea,prev,sizeof prea); int ans=d[n],mx=0; for(int i=prea[n];i;i=prea[e[i].from]){ e[i].dis*=2; e[i^1].dis*=2; dijkstra(); if(d[n]-ans>mx)mx=d[n]-ans; e[i].dis/=2; e[i^1].dis/=2; } printf("%d\n",mx); return 0; }
时间: 2024-10-10 09:56:00