您的位置:首页 > 其它

POJ 3463 Sightseeing (次短路,Dijkstra拓展)

2014-01-25 21:35 295 查看
据说用 A* 求 k 短路,令 k = 2 ,会爆栈。

做这道题目主要还是学习为主。。

显然求最短路和次短路的数量,再判断二者是不是差 1 即可。

由于要求次短路,对 Dijkstra 进行修改。

dis[] 数组不再只存最短路,而是用二维数组同时存最短路和次短路,初始化只有起点 s 的最短路是 0,其他均为 inf

用 cnt[][2] 来计数,第一维伟最短路数量,第二维为次短路数量,初始化起点最短路为 1,其他为 0。

存在队列里的”状态“应该包括:1、结点标号 num 2、标签 flag:最短路还是次短路(后面解释为什么这样)

每次弹出  dis[num][flag] 最小的状态,表示 num 的 flag 路径 已经找到,其正确性同理于原始的 Dijkstra。

对结点 num 的邻接点进行松弛。

每次的松弛分为:1、比邻接点的最短路还短

2、等于最短路

3、大于最短路小于次短路

4、等于次短路

分别进行相应操作即可。

这里和 A* 不一样,存在队列里的”状态“,不应该包含相应的计数的值,因为 Dijkstra 保证每个点的每种路径只出队一次,故当时的 dis 和 num  就是我们要用的(出队的一定是该路径的最优解,而 dis 最终也一定是最优解覆盖的,cnt 同理)

用结点 cur 松弛结点 tar 时,应该把对应的 cnt 传过去,因为如果从 A···B 有 n 条路,则用路径 A···B 松弛得到的的 A···B→C 松弛后也应该标记为 n 条或 cnt + n 条(根据具体情况)。

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

const int maxv = 1100, maxe = 11000, inf = 0x3f3f3f3f;

int n, m, s, t;
int head[maxv], next[maxe];
int fr[maxe], to[maxe], wt[maxe];

void read()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) {
scanf("%d%d%d", &fr[i], &to[i], &wt[i]);
fr[i]--; to[i]--;
next[i] = head[fr[i]];
head[fr[i]] = i;
}
scanf("%d%d", &s, &t);
s--; t--;
}

int dis[maxv][2];
int cnt[maxv][2];
bool done[maxv][2];

typedef struct Node {
int num, tag;
Node(int n, int t) {
num = n;
tag = t;
}
bool operator<(Node b)const{
return dis[num][tag] > dis[b.num][b.tag];
}
}Node;

priority_queue<Node> que;

int dijkstra()
{
memset(done, false, sizeof(done));
memset(dis, 0x3f, sizeof(dis));
memset(cnt, 0, sizeof(cnt));
dis[s][0] = 0;
cnt[s][0] = 1;
que.push(Node(s, 0));
while(!que.empty()) {
Node cn = que.top(); que.pop();
int cur = cn.num, cf = cn.tag;
if(done[cur][cf]) continue;
done[cur][cf] = true;
for(int i = head[cur]; i != -1; i = next[i]) {
int tar = to[i];
if(dis[cur][cf] + wt[i] < dis[tar][0]) {
dis[tar][1] = dis[tar][0];
cnt[tar][1] = cnt[tar][0];
if(dis[tar][1] < inf) que.push(Node(tar, 1));
dis[tar][0] = dis[cur][cf] + wt[i];
cnt[tar][0] = cnt[cur][cf];
que.push(Node(tar, 0));
}
else if(dis[cur][cf] + wt[i] == dis[tar][0])
cnt[tar][0] += cnt[cur][cf];
else if(dis[cur][cf] + wt[i] < dis[tar][1]) {
dis[tar][1] = dis[cur][cf] + wt[i];
cnt[tar][1] = cnt[cur][cf];
que.push(Node(tar, 1));
}
else if(dis[cur][cf] + wt[i] == dis[tar][1])
cnt[tar][1] += cnt[cur][cf];
}
}
int ret = cnt[t][0];
if(dis[t][1] - dis[t][0] == 1) ret += cnt[t][1];
return ret;
}

int main()
{
int ca;

scanf("%d", &ca);
while(ca--) {
read();
printf("%d\n", dijkstra());
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: