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 ...
随机推荐
- Vue页面间传值,以及客户端数据存储
初学Vue,遇到了页面传值的问题,大概网上学习了解了一下,在此跟大家分享一下学习心得,欢迎批评指正. 一.参数传值 如果是简单的页面传值,比如传一个id到详情页等等,推荐使用参数传值. 这里页面是通过 ...
- jquery学习之$(document).ready()
参考资料: 1.W3School在线教程:http://www.w3school.com.cn/jquery/event_ready.asp 2.某人博客园:http://www.cnblogs.co ...
- background使用
background-position 有两个参数,定义背景图片起始位置可选值有: center top left right bottom px % background-size 可以用 px % ...
- Java冒泡,快速,插入,选择排序^_^+二分算法查找
这段时间在学Java,期间学到了一些排序和查找方法.特此写来和大家交流,也方便自己的日后查看与复习. 1.下边是Java的主类: public class Get { public static vo ...
- Visual C++ 6.0的界面介绍
双击Visual C++ 6.0安装目录下的文件启动Visual C++ 6.0,通过“文件”→“新建”可新建一个Win32 Console Application项目.创建好项目后,显示Visu ...
- 在命令提示符窗口下(cmd)使用指令操作并编译java代码,运行java编译代码
使用cmd操作java代码,编译.java文件,运行.class文件. 操作步骤: 1:创建一个文件夹: 例如:在e盘根目录(\)下面创建一个名为Hello的文件夹: 使用md指令:如图 在e盘中会生 ...
- dotnetnuke7.x 弹出窗口的皮肤加载问题
皮肤文件夹中必须要有popUpSkin.ascx才会正常加载skin.css文件
- C#中SetWindowPos函数详解
[DllImport("user32.dll")] private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWnd ...
- 微信公众号API使用总结
官网: https://mp.weixin.qq.com/ API: http://mp.weixin.qq.com/wiki/home/index.html 接口调试工具:h ...
- ROS:Nvidia Jetson TK1开发平台
原文链接: http://wiki.ros.org/NvidiaJetsonTK1 1. Nvidia Jetson TK1 Jetson TK1 comes pre-installed with L ...