题目大意:求两点间最短路与长度为最短路长度+1的路径的条数之和。

方法1:最短路径+DP

首先求出ST间最短路径,然后根据递归式记忆化搜索(因此还要构造反向图)。

我们知道到达终点的路径长度最长为maxDist(T)=minDist(T)+1,而与终点相连的节点的路径长度最长为maxDist(T)-Weight(e)。这些节点与更前面的节点也是如此。于是我们从终点开始递归,利用PathCnt(v)=sum(PathCnt(u)) (PathCnt(u)=|{Dist(u)|Dist(u)<=maxDist(u)}|)。

初值注意不能直接PathCnt(S)设为1,因为S点也可能在一个环内。因此我们应当建点S'->S,边权为0。

代码:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std; #define LOOP(i,n) for(int i=1; i<=n; i++)
const int MAX_NODE = 1010, MAX_EDGE = 10010 * 2, INF = 0x3f3f3f3f; struct Node;
struct Edge; struct Node
{
int Id, Dist, PathCnt[2];
bool Inq;
Edge *Head, *RevHead;
}_nodes[MAX_NODE], *Start, *Target;
int _vCount; struct Edge
{
int Weight;
Node *From, *To;
Edge *Next;
}*_edges[MAX_EDGE];
int _eCount; void Init(int vCount)
{
_vCount = vCount;
_eCount = 0;
memset(_nodes, 0, sizeof(_nodes));
} void SetST(int sId, int tId)
{
Start = sId + _nodes;
Target = tId + _nodes;
} Edge *NewEdge()
{
_eCount++;
return _edges[_eCount] ? _edges[_eCount] : _edges[_eCount] = new Edge();
} void AddEdge(Node *from, Node *to, int weight, bool IsRev)
{
Edge *e = NewEdge();
e->From = from;
e->To = to;
e->Weight = weight;
Edge *&head = IsRev ? from->RevHead : from->Head;
e->Next = head;
head = e;
} void Build(int uId, int vId, int weight)
{
Node *from = uId + _nodes, *to = vId + _nodes;
from->Id = uId;
to->Id = vId;
AddEdge(from, to, weight, false);
AddEdge(to, from, weight, true);
} void SPFA()
{
static queue<Node*> q;
LOOP(i, _vCount)
{
_nodes[i].Dist = INF;
_nodes[i].Inq = false;
}
Start->Dist = 0;
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 CntPath(Node *cur, int maxDist)
{
if (cur->Dist > maxDist)
return 0;
int &pathCnt = cur->PathCnt[maxDist - cur->Dist];
if (pathCnt != -1)
return pathCnt;
if (cur == Start)
return 1;
pathCnt = 0;
for (Edge *e = cur->RevHead; e; e = e->Next)
pathCnt += CntPath(e->To, maxDist - e->Weight);
return pathCnt;
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
int testCase, totNode, totEdge, uId, vId, weight, sId, tId;
scanf("%d", &testCase);
while (testCase--)
{
scanf("%d%d", &totNode, &totEdge);
Init(totNode + 1);
LOOP(i, totEdge)
{
scanf("%d%d%d", &uId, &vId, &weight);
Build(uId, vId, weight);
}
scanf("%d%d", &sId, &tId);
Build(totNode + 1, sId, 0);
SetST(totNode + 1, tId);
SPFA();
LOOP(i, _vCount)
_nodes[i].PathCnt[0] = _nodes[i].PathCnt[1] = -1;
printf("%d\n", CntPath(Target, Target->Dist + 1));
}
return 0;
}

方法2:Dijkstra

同时更新一个节点的最短路径长度和次短路长度以及它们的个数。优先队列里维护节点,key值为节点最短路长度或次短路长度。究竟是哪个长度我们不用管它,该节点能更新最短路就更新最短路,否则看看能不能更新次短路。

注意:1.如果v的newDist与v原来的路径长度相等,更新完路径个数后不要入队!队列只维护最短路径或次短路径。2.更新完了v最短路,v次短路也更新了,所以要把v节点以key值为最短路长度和次短路长度入队两次。3.优先队列是大根堆。

代码:

#include <cstdio>
#include <cstring>
#include <cassert>
#include <queue>
using namespace std; #define LOOP(i,n) for(int i=1; i<=n; i++)
#define _1st 0
#define _2nd 1
const int MAX_NODE = 1010, MAX_EDGE = 10010 * 2, INF = 0x3f3f3f3f; struct Node;
struct Edge; struct Node
{
int Id, Dist[2], Cnt[2];
bool Done[2];
Edge *Head;
}_nodes[MAX_NODE], *Start, *Target;
int _vCount; struct Edge
{
int Weight;
Node *From, *To;
Edge *Next;
}*_edges[MAX_EDGE];
int _eCount; struct HeapNode
{
Node *Org;
int Dist;
bool Is2nd;
bool operator <(const HeapNode a)const { return Dist > a.Dist; }
HeapNode(Node *a, bool isSec):Org(a),Dist(a->Dist[isSec]),Is2nd(isSec){}
}; void Init(int vCount)
{
memset(_nodes, 0, sizeof(_nodes));
_vCount = vCount;
_eCount = 0;
} void SetST(int sId, int tId)
{
Start = sId + _nodes;
Target = tId + _nodes;
} Edge *NewEdge()
{
_eCount++;
if (_edges[_eCount])
return _edges[_eCount];
else
return _edges[_eCount] = new Edge();
} Edge *AddEdge(Node *from, Node *to, int weight)
{
Edge *e = NewEdge();
e->From = from;
e->To = to;
e->Weight = weight;
e->Next = e->From->Head;
e->From->Head = e;
return 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);
} void Dijkstra()
{
static priority_queue<HeapNode> q;
LOOP(i, _vCount)
{
_nodes[i].Dist[0] = _nodes[i].Dist[1] = INF;
_nodes[i].Done[0] = _nodes[i].Done[1] = false;
}
Start->Dist[_1st] = 0;
Start->Cnt[_1st] = 1;
q.push(HeapNode(Start, false));
while (!q.empty())
{
HeapNode cur = q.top();
q.pop();
Node *u = cur.Org;
if (u->Done[cur.Is2nd])
continue;
u->Done[cur.Is2nd] = true;
for (Edge *e = u->Head; e; e = e->Next)
{
int newDist = cur.Dist + e->Weight;
if (newDist < e->To->Dist[_1st])
{
e->To->Cnt[_2nd] = e->To->Cnt[_1st];
e->To->Dist[_2nd] = e->To->Dist[_1st];
e->To->Cnt[_1st] = u->Cnt[cur.Is2nd];
e->To->Dist[_1st] = newDist;
q.push(HeapNode(e->To, _1st));
q.push(HeapNode(e->To, _2nd));
}
else if (newDist > e->To->Dist[_1st] && newDist < e->To->Dist[_2nd])
{
e->To->Cnt[_2nd] = u->Cnt[cur.Is2nd];
e->To->Dist[_2nd] = newDist;
q.push(HeapNode(e->To, _2nd));
}
else if (newDist == e->To->Dist[_1st])
e->To->Cnt[_1st] += u->Cnt[cur.Is2nd];
else if (newDist == e->To->Dist[_2nd])
e->To->Cnt[_2nd] += u->Cnt[cur.Is2nd];
}
}
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
freopen("c:\\noi\\source\\output.txt", "w", stdout);
#endif
int testCase, totNode, totEdge, uId, vId, weight, sId, tId;
scanf("%d", &testCase);
while (testCase--)
{
scanf("%d%d", &totNode, &totEdge);
Init(totNode);
LOOP(i, totEdge)
{
scanf("%d%d%d", &uId, &vId, &weight);
Build(uId, vId, weight);
}
scanf("%d%d", &sId, &tId);
SetST(sId, tId);
Dijkstra();
printf("%d\n", Target->Cnt[_1st] + ((Target->Dist[_2nd] == Target->Dist[_1st] + 1) ? Target->Cnt[_2nd] : 0));
}
return 0;
}

  错误做法:SPFA同时更新最短路和次短路。

为什么Dijkstra就可以?因为u出队时,由于Dijkstra的贪心,u本身就更新完了,无后顾之忧;而SPFA中,u还没更新完就要往下更新。u往下更新以后,如果以后运算过程中u自己再被更新,此时再由u往下更新v,v节点就错了。

POJ3463 Sightseeing的更多相关文章

  1. POJ---3463 Sightseeing 记录最短路和次短路的条数

    Sightseeing Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9247   Accepted: 3242 Descr ...

  2. [POJ3463] Sightseeing(次短路 Heap + Dijkstra)

    传送门 用dijkstra比较好,spfa可能有的重复 dis[x][2]:dis[x][0]表示起点到x的最短路.dis[x][1]表示起点到x的次短路: tot[x][2]:tot[x][0]表示 ...

  3. poj3463 Sightseeing——次短路计数

    题目:http://poj.org/problem?id=3463 次短路计数问题,在更新最短路的同时分类成比最短路短.长于最短路而短于次短路.比次短路长三种情况讨论一下,更新次短路: 然而其实不必被 ...

  4. POJ 1637 Sightseeing tour

    Sightseeing tour Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9276   Accepted: 3924 ...

  5. 【POJ3621】Sightseeing Cows

    Sightseeing Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8331   Accepted: 2791 ...

  6. poj1637 Sightseeing tour

    Sightseeing tour Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 8859   Accepted: 3728 ...

  7. POJ 1637 Sightseeing tour (混合图欧拉路判定)

    Sightseeing tour Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6986   Accepted: 2901 ...

  8. POJ 1637 Sightseeing tour (混合图欧拉回路)

    Sightseeing tour   Description The city executive board in Lund wants to construct a sightseeing tou ...

  9. HDU 1688 Sightseeing&HDU 3191 How Many Paths Are There(Dijkstra变形求次短路条数)

    Sightseeing Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

随机推荐

  1. NoSQL概念

    NoSQL是非关系型数据库,即not only sql,key/value键值对存储. 现有Nosql DB产品:Redis/MongoDB/Memcached等等. SQL Sever是关系型数据库 ...

  2. 【转】js中几种实用的跨域方法原理详解

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  3. WPF度量系統

    和Winform不同,WPF的度量單位不是像素,而是設備無關單位DIU,其大小總是1/96吋 那麽,WPF中一個寬度爲96的按鈕,到底是多少個像素呢? 答:取決於系統DPI. 計算公式爲:實際像素 = ...

  4. 三维重建:SLAM的尺度和方法论问题

    百度百科的定义.此文引用了其他博客的一些图像,如有侵权,邮件联系删除. 作为算法的SLAM,被称为同步相机位姿确定和地图构建.作为一个工程的SLAM,有众多的算法. 在计算机视觉中, 三维重建是指根据 ...

  5. HDU_1269_tarjan求强连通分量

    迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  6. day34-2 类和对象(重点)

    目录 类 定义类和对象 __dict__ 和__class__ 创建对象时的底层运作 定义对象独有的特征 init __slots__(了解) 给对象添加属性时的底层运作 类 分类/类别 上述的代码( ...

  7. eoLinker上线两周年+ AMS V4.0 发布:全新UI界面,带来领先的API开发管理解决方案!

    2018年7月,eoLinker 发布了<eoLinker AMS 2018年年中用户调研问卷>,前后经历一周的时间,共收集到超过1000份有效调查问卷.超过300个有效改进意见. eoL ...

  8. 51nod1081 子段求和

    给出一个长度为N的数组,进行Q次查询,查询从第i个元素开始长度为l的子段所有元素之和. 例如,1 3 7 9 -1,查询第2个元素开始长度为3的子段和,1 {3 7 9} -1.3 + 7 + 9 = ...

  9. 洛谷P1464 Function

    对于一个递归函数w(a,b,c)w(a,b,c) 如果a \le 0a≤0 or b \le 0b≤0 or c \le 0c≤0就返回值11. 如果a>20a>20 or b>20 ...

  10. 10.shard、replica机制及单node下创建index

    主要知识点     1.shard&replica机制梳理 2.单node环境下创建index的情况     1.shard&replica机制再次梳理     (1)index包含多 ...