POJ3255 Roadblocks 严格次短路
题目大意:求图的严格次短路。
方法1:
SPFA,同时求单源最短路径和单源次短路径。站在节点u上放松与其向量的v的次短路径时时,先尝试由u的最短路径放松,再尝试由u的次短路径放松(该两步并非非此即彼)。
由u的最短路径放松:
if(u->Dist + e->Weight < v->Dist)
v->Dist2=v->Dist;
//此处隐藏最短路放松。次短路不在此固定,Dist2可能在由u次短路放松时被放松得更短 if(u->Dist + e->Weight > v->Dist && u->Dist + e->Weight < v->Dist2)
v->Dist2=u->Dist+e->Weight;
由u的次短路经放松:
if(u->Dist2 + e->Weight > v->Dist && u->Dist2 + e->Weight < v->Dist2)
v->Dist2=u->Dist2 + e->Weight;
完整代码:
#include <cstdio>
#include <cstring>
#include <cassert>
#include <queue>
using namespace std; #define LOOP(i,n) for(int i=1; i<=n; i++)
const int MAX_NODE = , MAX_EDGE = * , INF = 0x3f3f3f3f; struct Node;
struct Edge; struct Node
{
int Id, Dist, Dist2;
bool Inq;
Edge *Head;
}_nodes[MAX_NODE], *Start, *Target;
int _vCount; struct Edge
{
int Weight;
Node *From, *To;
Edge *Next;
Edge() {}
Edge(Node *from, Node *to, Edge *next, int weight) :
From(from), To(to), Next(next), Weight(weight){}
}*_edges[MAX_EDGE];
int _eCount; void Init(int vCount)
{
memset(_nodes, , sizeof(_nodes));
_vCount = vCount;
_eCount = ;
Start = + _nodes;
Target = vCount + _nodes;
} void AddEdge(Node *from, Node *to, int weight)
{
Edge *e = _edges[++_eCount] = new Edge(from, to, from->Head, weight);
e->From->Head = e;
} void Build(int uId, int vId, int weight)
{
Node *u = uId + _nodes, *v = vId + _nodes;
u->Id = uId;
v->Id = vId;
AddEdge(u, v, weight);
AddEdge(v, u, weight);
} void SPFA()
{
LOOP(i, _vCount)
_nodes[i].Dist = _nodes[i].Dist2 = INF;
static queue<Node*> q;
Start->Dist = ;
Start->Dist2 = INF;
Start->Inq = true;
q.push(Start);
while (!q.empty())
{
Node *u = q.front();
q.pop();
u->Inq = false;
for (Edge *e = u->Head; e; e = e->Next)
{
bool relaxOk = false;
if (u->Dist + e->Weight < e->To->Dist)
{
e->To->Dist2 = e->To->Dist;
e->To->Dist = u->Dist + e->Weight;
relaxOk = true;
}
else if (u->Dist + e->Weight > e->To->Dist && u->Dist + e->Weight < e->To->Dist2)
{
e->To->Dist2 = u->Dist + e->Weight;
relaxOk = true;
}
if (u->Dist2 + e->Weight < e->To->Dist2)
{
e->To->Dist2 = u->Dist2 + e->Weight;
relaxOk = true;
}
if (relaxOk && !e->To->Inq)
{
e->To->Inq = true;
q.push(e->To);
}
}
}
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
int testCase, totNode, totEdge, uId, vId, weight, sId, tId;
scanf("%d%d", &totNode, &totEdge);
Init(totNode);
LOOP(i, totEdge)
{
scanf("%d%d%d", &uId, &vId, &weight);
Build(uId, vId, weight);
}
SPFA();
printf("%d\n", Target->Dist2);
return ;
}
方法2:
Dijkstra。其需用到优先队列,维护一对数据:一个节点u以及它到原点的路径d。d可以是u的最短路径,也可以是u的次短路径,但我们不用管它,我们只管放松。它能放松v最短路就放松v最短路,再不行看看它能不能放松v次短路。
完整代码:
#include <cstdio>
#include <cstring>
#include <cassert>
#include <queue>
#include <vector>
#include <functional>
using namespace std; #define LOOP(i,n) for(int i=1; i<=n; i++)
const int MAX_NODE = , MAX_EDGE = * , INF = 0x3f3f3f3f; struct Node;
struct Edge; struct Node
{
int Id, Dist, Dist2;
bool Inq;
Edge *Head;
}_nodes[MAX_NODE], *Start, *Target;
int _vCount; struct Edge
{
int Weight;
Node *From, *To;
Edge *Next;
Edge() {}
Edge(Node *from, Node *to, Edge *next, int weight) :
From(from), To(to), Next(next), Weight(weight) {}
}*_edges[MAX_EDGE];
int _eCount; void Init(int vCount)
{
memset(_nodes, , sizeof(_nodes));
_vCount = vCount;
_eCount = ;
Start = + _nodes;
Target = vCount + _nodes;
} void AddEdge(Node *from, Node *to, int weight)
{
Edge *e = _edges[++_eCount] = new Edge(from, to, from->Head, weight);
e->From->Head = e;
} void Build(int uId, int vId, int weight)
{
Node *u = uId + _nodes, *v = vId + _nodes;
u->Id = uId;
v->Id = vId;
AddEdge(u, v, weight);
AddEdge(v, u, weight);
} #define Pair pair<int,Node*>
void Dijkstra()
{
static priority_queue<Pair, vector<Pair>, greater<Pair>> q;
LOOP(i, _vCount)
_nodes[i].Dist = _nodes[i].Dist2 = INF;
Start->Dist = ;
q.push(Pair(, Start));
while (!q.empty())
{
Pair cur = q.top();
q.pop();
Node *u = cur.second;
int prevDist = cur.first;
//printf("prevDist %d\n", prevDist);
assert(prevDist >= u->Dist);
for (Edge *e = u->Head; e; e = e->Next)
{
if (prevDist + e->Weight < e->To->Dist)
{
e->To->Dist2 = e->To->Dist;
e->To->Dist = prevDist + e->Weight;
q.push(Pair(e->To->Dist, e->To));
}
else if (e->To->Dist < prevDist+e->Weight
&&prevDist+e->Weight < e->To->Dist2)
{
e->To->Dist2 = prevDist + e->Weight;
q.push(Pair(e->To->Dist2, e->To));
}
}
}
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
int testCase, totNode, totEdge, uId, vId, weight, sId, tId;
scanf("%d%d", &totNode, &totEdge);
Init(totNode);
LOOP(i, totEdge)
{
scanf("%d%d%d", &uId, &vId, &weight);
Build(uId, vId, weight);
}
Dijkstra();
printf("%d\n", Target->Dist2);
return ;
}
方法3:
我们假设一条边e在次短路径内,知道这条次短路径长度d[e]是多少。那么,我们枚举每个e,求出min{d[e]}即可。具体我们需要求出每一个节点到原点的最短路径和到汇点的最短路径。这样,d[e]=e->From->DistS + e->Weight + e->To->DistT。这样求出的d[e]可能与最短路径相等。此时怎样把它转化成次短路?只能将e重复走一遍!这样,d[e]'=e->From->DistS + e->Weight * 2 + e->From->DistT。
完整代码:
#include <cstdio>
#include <cstring>
#include <cassert>
#include <queue>
#include <vector>
#include <functional>
using namespace std; #define LOOP(i,n) for(int i=1; i<=n; i++)
const int MAX_NODE = , MAX_EDGE = * , INF = 0x3f3f3f3f; struct Node;
struct Edge; struct Node
{
int Id, Dist, Dist2;
bool Inq;
Edge *Head;
}_nodes[MAX_NODE], *Start, *Target;
int _vCount; struct Edge
{
int Weight;
Node *From, *To;
Edge *Next;
Edge() {}
Edge(Node *from, Node *to, Edge *next, int weight) :
From(from), To(to), Next(next), Weight(weight) {}
}*_edges[MAX_EDGE];
int _eCount; void Init(int vCount)
{
memset(_nodes, , sizeof(_nodes));
_vCount = vCount;
_eCount = ;
Start = + _nodes;
Target = vCount + _nodes;
} void AddEdge(Node *from, Node *to, int weight)
{
Edge *e = _edges[++_eCount] = new Edge(from, to, from->Head, weight);
e->From->Head = e;
} void Build(int uId, int vId, int weight)
{
Node *u = uId + _nodes, *v = vId + _nodes;
u->Id = uId;
v->Id = vId;
AddEdge(u, v, weight);
AddEdge(v, u, weight);
} void SPFA(Node *start)
{
LOOP(i, _vCount)
{
_nodes[i].Dist = INF;
_nodes[i].Inq = false;
}
static queue<Node*> q;
start->Dist = ;
start->Inq = true;
q.push(start);
while (!q.empty())
{
Node *u = q.front();
q.pop();
u->Inq = false;
for (Edge *e = u->Head; e; e = e->Next)
{
if (u->Dist + e->Weight < e->To->Dist)
{
e->To->Dist = u->Dist + e->Weight;
if (!e->To->Inq)
{
e->To->Inq = true;
q.push(e->To);
}
}
}
}
} int Proceed()
{
SPFA(Target);
int minDist = Start->Dist, ans = INF;
LOOP(i, _vCount)
_nodes[i].Dist2 = _nodes[i].Dist;
SPFA(Start);
LOOP(i, _eCount)
{
Edge *e = _edges[i];
int temp = e->From->Dist + e->Weight + e->To->Dist2;
if (minDist < temp&&temp < ans)
ans = temp;
else
{
temp = e->From->Dist + e->From->Dist2 + e->Weight * ;
ans = min(ans, temp);
}
}
return ans;
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
int testCase, totNode, totEdge, uId, vId, weight, sId, tId;
scanf("%d%d", &totNode, &totEdge);
Init(totNode);
LOOP(i, totEdge)
{
scanf("%d%d%d", &uId, &vId, &weight);
Build(uId, vId, weight);
}
printf("%d\n", Proceed());
return ;
}
POJ3255 Roadblocks 严格次短路的更多相关文章
- POJ3255 Roadblocks 【次短路】
Roadblocks Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 7760 Accepted: 2848 Descri ...
- POJ3255 Roadblocks [Dijkstra,次短路]
题目传送门 Roadblocks Description Bessie has moved to a small farm and sometimes enjoys returning to visi ...
- poj3255 Roadblocks 次短路
Roadblocks Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10098 Accepted: 3620 Descr ...
- 【POJ3255/洛谷2865】[Usaco2006 Nov]路障Roadblocks(次短路)
题目: POJ3255 洛谷2865 分析: 这道题第一眼看上去有点懵-- 不过既然要求次短路,那估计跟最短路有点关系,所以就拿着优先队列优化的Dijkstra乱搞,搞着搞着就通了. 开两个数组:\( ...
- 【POJ - 3255】Roadblocks(次短路 Dijkstra算法)
Roadblocks 直接翻译了 Descriptions Bessie搬到了一个新的农场,有时候他会回去看他的老朋友.但是他不想很快的回去,他喜欢欣赏沿途的风景,所以他会选择次短路,因为她知道一定有 ...
- poj3255 Roadblocks
Roadblocks Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 13594 Accepted: 4783 Descr ...
- POJ 3255 Roadblocks (次短路模板)
Roadblocks http://poj.org/problem?id=3255 Time Limit: 2000MS Memory Limit: 65536K Descriptio ...
- 【POJ】3255 Roadblocks(次短路+spfa)
http://poj.org/problem?id=3255 同匈牙利游戏. 但是我发现了一个致命bug. 就是在匈牙利那篇,应该dis2单独if,而不是else if,因为dis2和dis1相对独立 ...
- 【洛谷 P2865】 [USACO06NOV]路障Roadblocks(最短路)
题目链接 次短路模板题. 对每个点记录最短路和严格次短路,然后就是维护次值的方法了. 和这题一样. #include <cstdio> #include <queue> #in ...
随机推荐
- SQL连接其它服务器操作
Exec sp_droplinkedsrvlogin ZYB,Null --删除映射(录与链接服务器上远程登录之间的映射) Exec sp_dropserver ZYB --删除远程服务器链接 EXE ...
- Spring Boot (3) 热部署devtools
热部署:当发现程序修改时自动启动应用程序. spring boot为开发者提供了一个名为spring-boot-devtools的模块来使sring boot应用支持热部署,提高开发者的开发效率,无需 ...
- Struts2 在拦截器中向Action传参
struts.xml配置文件: <package name="system-default" extends="struts-default" abstr ...
- 阶乘问题-----sum随变量改变而改变
- 安卓代码迁移:Program "sh" not found in PATH
Description Resource Path Location Type Program "sh" not found in PATH 参考链 ...
- ROS:ubuntu-Ros使用OrbSLAM
一般无误的官方连接:https://github.com/raulmur/ORB_SLAM ubuntu16.04没有多少改变,还是使用kinetic老代替indigo Related Publica ...
- 【转】【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 特殊问题和实战经验(五)
原文地址:http://www.cnblogs.com/baiboy/p/orc5.html 阅读目录 目录 共享存储 时间一致性 互联网络(或者私有网络.心跳线) 固件.驱动.升级包的一致性 共 ...
- ListUtil集合操作常用方法类
* 集合操作常用方法类. * <p> * * @author 柯 */ public class ListUtil { /** * 判断List不为空,非空返回true,空则返回false ...
- 11.5 【Linq 】连接
11.5.1 使用 join 子句的内连接 如果你打算把一个巨大的序列连接到一个极小的序列上,应尽可能把小序列作为右边序列 class Program { static void Main(strin ...
- 51nod1134 最长递增子序列【动态规划】
给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递增的) 例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10. Input 第1行:1个数N ...