POJ 3463 Sightseeing

POJ_3463

    题目要求去求最短路以及比最短路大1的所有路径的数量。

    如果单求最短路数量的话,我们可以直接用SPFA+dp或者dij+dp去做,而这个题目不过是多了一个相当于次短路的数量的问题,因此我们可以把每个点拆成两个点,一个点记录最短路的距离及路径数量,另一个记录次短路距离及路径数量,用dij+dp去处理应该更方便一些。

    每次更新时,如果比最短路小,就把次短路的相关数据先更新成之前的最短路的数据,然后再更新最短路的数据,如果比最短路大但比次短路小就只需更新次短路的数据,其他的一些情况就比较好分析了。

#include<stdio.h>
#include<string.h>
#define MAXD 1010
#define MAXM 10010
#define INF 0x3f3f3f3f
int N, M, D, S, T, e, first[MAXD], next[MAXM], v[MAXM], w[MAXM], tree[8 * MAXD], d[2 * MAXD], ans[2 * MAXD];
void init()
{
int i, j, k, x, y, z;
e = 0;
scanf("%d%d", &N, &M);
memset(first + 1, -1, sizeof(first[0]) * N);
for(i = 0; i < M; i ++)
{
scanf("%d%d%d", &x, &y, &z);
v[e] = y, w[e] = z;
next[e] = first[x];
first[x] = e;
++ e;
}
}
void update(int i)
{
for(; i ^ 1; i >>= 1)
tree[i >> 1] = d[tree[i]] < d[tree[i ^ 1]] ? tree[i] : tree[i ^ 1];
}
void solve()
{
int i, j, k, x, y1, y2;
for(D = 1; D < 2 * N + 4; D <<= 1);
memset(d, 0x3f, sizeof(d));
memset(tree, 0, sizeof(tree));
for(i = 2; i <= 2 * N + 1; i ++)
tree[D + i] = i;
scanf("%d%d", &S, &T);
d[S << 1] = 0;
ans[S << 1] = 1;
update(D + (S << 1));
while(d[tree[1]] != INF)
{
x = tree[1];
if(x == ((T << 1) ^ 1))
break;
for(i = first[x >> 1]; i != -1; i = next[i])
{
y1 = v[i] << 1, y2 = (v[i] << 1) ^ 1;
if(d[x] + w[i] <= d[y1])
{
if(d[x] + w[i] < d[y1])
{
d[y2] = d[y1], ans[y2] = ans[y1];
update(D + y2);
d[y1] = d[x] + w[i], ans[y1] = ans[x];
update(D + y1);
}
else
ans[y1] += ans[x];
}
else if(d[x] + w[i] <= d[y2])
{
if(d[x] + w[i] < d[y2])
{
d[y2] = d[x] + w[i], ans[y2] = ans[x];
update(D + y2);
}
else
ans[y2] += ans[x];
}
}
tree[x + D] = 0;
update(x + D);
}
printf("%d\n", ans[T << 1] + (d[(T << 1) ^ 1] == d[T << 1] + 1 ? ans[(T << 1) ^ 1] : 0));
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
init();
solve();
}
return 0;
}


原文地址:https://www.cnblogs.com/staginner/p/2404226.html