P2865 【[USACO06NOV]路障Roadblocks】(次短路)
算法
Dijkstra
要求次短路
那么在不考虑重复走一条边的情况下
肯定是把最短路中的一段改成另一段
至少要换另一条边到路径里
所以可以枚举所有不属于最短路的每条边(a,b)
那么dis(1,a)+(a,b)+ dis(b,n)就是一种可能的答案(记为S)
显然如果另一条不属于S的边更新S后会使S更长,就不可能为次短路了
那么只要对起点1和终点n分别跑Dijkstra就可以求出每个dis(1,a)和dis(b,n)
至于判断一条边是否在最短路上也很容易:
显然,如果dis(1,a)+(a,b)=dis(1,b),那么边(a,b)就在最短路径上
然后考虑重复走一条边情况(显然也只要考虑重复走一条边的情况)
也很简单,用贪心的思想
找到最短路径上最短的边(a,b),如果重复走一条边的情况为次短路,那么肯定是dis(1,n)+(a,b)*2 (走过去又走回来,要乘2)
如果(c,d)不是最短的边,那么dis(1,n)+(c,d)*2肯定大于dis(1,n)+(a,b)*2,就不可能是次短路
然后就可以了,实现时要注意一下细节
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
inline int read()
{
int res=;
char ch=getchar();
while(ch>''||ch<'')
ch=getchar();
while(ch>=''&&ch<='')
{
res=res*+ch-'';
ch=getchar();
}
return res;
}
struct node//存Dijkstra的优先队列中的数据
{
int u,v;//v为点的编号,u表示从起点到v的距离
bool operator < (const node &b) const{
return u>b.u;
}
};
priority_queue <node> q;//为Dijkstra开的优先队列
struct edge
{
int from,to,z;
}e[];
int fir[],cnt;//链式前向星存图
inline void add(int a,int b,int c)
{
e[++cnt].from=fir[a];
fir[a]=cnt;
e[cnt].to=b;
e[cnt].z=c;
}//加边
int n,m,ans=;
int dis[][];
//dis[][0]为起点到各个点的距离,dis[][1]为终点到各个点的距离
inline void dijk(int sta,int k)
//sta为开始点,k为dis的第二维
{
dis[sta][k]=;
node p;
p.u=; p.v=sta;
q.push(p);
while(q.empty()==)
{
int u=q.top().u,v=q.top().v;
q.pop();
if(u!=dis[v][k]) continue; //优化
for(int i=fir[v];i;i=e[i].from)
{
int to=e[i].to;
if(dis[to][k]>dis[v][k]+e[i].z)
{
dis[to][k]=dis[v][k]+e[i].z;
p.u=dis[to][k]; p.v=to;
q.push(p);
}
}
}
}//Dijkstra的模板
struct data
{
int x,y,z;
}d[];//存读入的数据
int main()
{
memset(dis,0x7f,sizeof(dis));
int a,b,c,mi=;//mi表示最短路径上最短的边长
cin>>n>>m;
for(int i=;i<=m;i++)
{
a=read(); b=read(); c=read();
d[i].x=a; d[i].y=b; d[i].z=c;
add(a,b,c); add(b,a,c);
}//读入
dijk(,); dijk(n,);//跑最短路
int mx=dis[n][];
for(int i=;i<=m;i++)
//考虑不重复走一条边的情况
{
int x=d[i].x,y=d[i].y;
if(dis[x][]+dis[y][]>dis[y][]+dis[x][]) swap(x,y);
//重要的细节,1到x的路径不能和y到n的路径重复
int s=dis[x][]+dis[y][];
if(s+d[i].z==mx) continue;//判断边(x,y)是否在最短路径上,如果在就不能选
ans=min(ans,s+d[i].z);//否则就尝试更新答案
}
for(int i=;i<=m;i++)
//考虑重复走一条边的情况,显然只要考虑在最短路径上的边
{
int x=d[i].x,y=d[i].y;
if(dis[x][]+dis[y][]>dis[y][]+dis[x][]) swap(x,y);
//同样,1到x的路径不能和y到n的路径重复
if(dis[x][]+dis[y][]+d[i].z!=mx) continue;//如果边(x,y)不在最短路径上就不能考虑
mi=min(mi,d[i].z);//尝试更新mi
}
ans=min(ans,mx+mi*);//答案取较小值
cout<<ans;
return ;
}
P2865 【[USACO06NOV]路障Roadblocks】(次短路)的更多相关文章
- 洛谷P2865 [USACO06NOV]路障Roadblocks——次短路
给一手链接 https://www.luogu.com.cn/problem/P2865 这道题其实就是在维护最短路的时候维护一下次短路就okay了 #include<cstdio> #i ...
- P2865 [USACO06NOV]路障Roadblocks
P2865 [USACO06NOV]路障Roadblocks 最短路(次短路) 直接在dijkstra中维护2个数组:d1(最短路),d2(次短路),然后跑一遍就行了. attention:数据有不同 ...
- 洛谷——P2865 [USACO06NOV]路障Roadblocks
P2865 [USACO06NOV]路障Roadblocks 题目描述 Bessie has moved to a small farm and sometimes enjoys returning ...
- 络谷 P2865 [USACO06NOV]路障Roadblocks
P2865 [USACO06NOV]路障Roadblocks 题目描述 Bessie has moved to a small farm and sometimes enjoys returning ...
- luogu2865 [USACO06NOV]路障Roadblocks 次短路
注意:如果是这么个写法,堆数组要开成n+m的. 为什么呢?设想一下从1到2有m条长度递减的路,这岂不是要入队m次-- #include <algorithm> #include <i ...
- POJ——T 3255 Roadblocks|| COGS——T 315. [POJ3255] 地砖RoadBlocks || 洛谷—— P2865 [USACO06NOV]路障Roadblocks
http://poj.org/problem?id=3255 Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 15680 ...
- 【洛谷 P2865】 [USACO06NOV]路障Roadblocks(最短路)
题目链接 次短路模板题. 对每个点记录最短路和严格次短路,然后就是维护次值的方法了. 和这题一样. #include <cstdio> #include <queue> #in ...
- 洛谷题解 P2865 【[USACO06NOV]路障Roadblocks】
链接:https://www.luogu.org/problemnew/show/P2865 题目描述 Bessie has moved to a small farm and sometimes e ...
- BZOJ 1726 洛谷 2865 [USACO06NOV]路障Roadblocks【次短路】
·求1到n的严格次短路. [题解] dijktra魔改?允许多次入队,改了次短路的值也要入队. #include<cstdio> #include<algorithm> #de ...
随机推荐
- PAT 1003 Emergency[图论]
1003 Emergency (25)(25 分) As an emergency rescue team leader of a city, you are given a special map ...
- javascript产生对象(不建议看)
产生对象的方式:一.new+构造函数1.JavaScript的内置构造函数,如Date(),Function(),Array(),Object()2.自定义的构造函数二.对象字面量{}三.继承 用 v ...
- Kaggle案例泰坦尼克号问题
泰坦里克号预测生还人口问题 泰坦尼克号问题背景 - 就是那个大家都熟悉的『Jack and Rose』的故事,豪华游艇倒了,大家都惊恐逃生,可是救生艇#### 的数量有限,无法人人都有,副船长发话了l ...
- 多项式函数插值:全域多项式插值(一)单项式基插值、拉格朗日插值、牛顿插值 [MATLAB]
全域多项式插值指的是在整个插值区域内形成一个多项式函数作为插值函数.关于多项式插值的基本知识,见“计算基本理论”. 在单项式基插值和牛顿插值形成的表达式中,求该表达式在某一点处的值使用的Horner嵌 ...
- Qt界面控件值获取异常处理
情景简述: 正常情况,我们从控件获取的值是OK的,但有时候就是奇怪的不对头,那么我们可以给获取后的值加上一个不痛不痒的函数,再返回,结果就OK了.至于原因嘛,[呲牙][呲牙] 比如: //正常情况 d ...
- 提高php代码质量的36个技巧的摘录
17.不要直接使用 $_SESSION 变量 简单例子: $_SESSION['username'] = $username; $username = $_SESSION['username']; ...
- python练习题,写一个方法 传进去列表和预期的value 求出所有变量得取值可能性(例如list为[1,2,3,4,5,6,12,19],value为20,结果是19+1==20只有一种可能性),要求时间复杂度为O(n)
题目:(来自光荣之路老师)a+b==valuea+b+c=valuea+b+c+d==valuea+b+c+d+...=valuea和b....取值范围都在0-value写一个方法 传进去列表和预期得 ...
- jsonp 方式处理跨域前后端代码如何配合?
JSONP(JSON with Padding)(json 数据填充)只支持GET请求 是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题. 跨域产生原因是浏览器的同源策略.( ...
- Linux服务器配置---ftp用户黑名单
用户黑白名单 一个Linux主机中会多个用户,而我们希望有些用户不能去访问ftp.ftp服务器可以通过配置文件“/etc/vsftpd/user_list”来设置一个用户列表,这个列表可以是黑名单,也 ...
- Linux基础命令---cmp
cmp 用字节的方式,比较两个文件是否存在差异,但是不保存运算结果.Cmp指令只会根据结果设置相关的标志位,这个指令之后往往会跟着一个条件跳转指令. 此命令的适用范围:RedHat.RHEL.Ubun ...