【POJ3255】【洛谷2865】[Usaco2006 Nov]路障Roadblocks(次短路)

来源:互联网 发布:linux查找目录命令 编辑:程序博客网 时间:2024/06/05 10:15

题目:POJ3255洛谷2865


分析:

这道题第一眼看上去有点懵……

不过既然要求次短路,那估计跟最短路有点关系,所以就拿着优先队列优化的Dijkstra乱搞,搞着搞着就通了。

开两个数组:dis存最短路,dis2存次短路

在松弛的时候同时更新两个数组,要判断三个条件

(u是当前考虑的点,v是与u有边相连的点,d(u,v)表示从u到v的边长)

1.如果dis[v]>dis[u]+d(u,v),则更新dis[v]

2.如果dis[v]<dis[u]+d(u,v)(不能取等,否则dis2[v]和dis[v]可能相等)且dis2[v]>dis[u]+d(u,v),则更新dis2[v]

3.如果dis2[v]>dis2[u]+d(u,v),则更新dis2[v](显然,如果2成立,3一定不成立)

如果上述三个条件中有任意一个成立,则将v入队。


还要注意一个地方:因为次短路可能会走“回头路”,所以一个点可以多次进队,所以不能使用vis数组判重。

以及起点的dis2不能初始化为0,因为起点的次短路一定是沿着与其相连的最短的边走出去再回来。


代码:

#include<cstdio>#include<algorithm>#include<queue> #include<cstring>#include<vector>using namespace std;int dis[5010],dis2[5010],n,m;struct point{int id;int dis;bool operator<(const point &b)const{return dis>b.dis;}};struct edge{int to;int w;};priority_queue<point>q;vector<edge>g[5010];int main(void){scanf("%d%d",&n,&m);for(int i=0;i<m;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);g[a].push_back((edge){b,c});g[b].push_back((edge){a,c});}memset(dis,0x3f3f3f3f,sizeof(dis));memset(dis2,0x3f3f3f3f,sizeof(dis2));dis[1]=0;q.push((point){1,0});while(!q.empty()){int u=q.top().id,d=q.top().dis;q.pop();if(d>dis2[u])continue;for(int i=0;i<g[u].size();i++){int v=g[u][i].to,w=g[u][i].w;bool flag=false;if(dis[v]>dis[u]+w)dis[v]=dis[u]+w,flag=true;if(dis[v]<dis[u]+w&&dis2[v]>dis[u]+w)dis2[v]=dis[u]+w,flag=true;if(dis2[v]>dis2[u]+w)dis2[v]=dis2[u]+w,flag=true;if(flag)q.push((point){v,dis[v]});}}printf("%d",dis2[n]);return 0;}


原创粉丝点击