POJ_3255

    本来想做POJ_2449的,结果自己想的这个算法TLE,看来解决那个题只能搞A*了。

    这个题目由于求次短路,第K短路的K就是2,比较小,所以可以直接用纯dij搞。我的思路就是把图上每个点搞一个容量不小于K的最大堆和最小堆,最小堆用于取到达当前该节点的第某短路值,最大堆用来保存前K小的最短路。

    最后为了每次能查询全局最小值,再把N个点放到一个线段树(最小堆)上即可,剩下的工作就是进行dij的过程了,当访问终点的次数达到第K次时break即可,这时就是第K短路的值了。

    当然,这么做其实是麻烦了,因为实际上K为2,所以可以直接把一个点拆成两个点,一个存当前最短路值,一个存次短路值即可。

#include<stdio.h>
#include<string.h>
#define MAXD 5010
#define MAXM 200010
#define MAXT 5
#define INF 0x3f3f3f3f
int DI, DO, N, M, K, S, T, first[MAXD], next[MAXM], v[MAXM], w[MAXM], tree[4 * MAXD], e;
struct Tree
{
int min, min_tree[MAXT], max_tree[MAXT], a[MAXT];
void init()
{
int i;
min = INF;
for(i = 0; i < DI; i ++)
{
min_tree[i + DI] = max_tree[i + DI] = i;
a[i] = INF;
}
for(i = DI - 1; i > 0; i --)
{
min_tree[i] = min_tree[i << 1];
max_tree[i] = max_tree[i << 1];
}
}
void update_min(int i)
{
for(; i ^ 1; i >>= 1)
min_tree[i >> 1] = a[min_tree[i]] < a[min_tree[i ^ 1]] ? min_tree[i] : min_tree[i ^ 1];
}
void update_max(int i)
{
for(; i ^ 1; i >>= 1)
max_tree[i >> 1] = a[max_tree[i]] > a[max_tree[i ^ 1]] ? max_tree[i] : max_tree[i ^ 1];
}
int Insert(int x)
{
int k = max_tree[1];
if(x < a[k])
{
a[k] = x, update_max(DI + k), update_min(DI + k);
if(x < min)
{
min = x;
return 1;
}
}
return 0;
}
void Delete()
{
int k = min_tree[1];
a[k] = INF, update_min(DI + k);
min = a[min_tree[1]];
}
}t[2 * MAXD];
void add(int x, int y, int z)
{
w[e] = z, v[e] = y;
next[e] = first[x], first[x] = e;
++ e;
}
void init()
{
int i, j, k, x, y, z;
for(DO = 1; DO <= N; DO <<= 1);
memset(first + 1, -1, sizeof(first[0]) * N);
e = 0;
for(i = 0; i < M; i ++)
{
scanf("%d%d%d", &x, &y, &z);
add(x, y, z), add(y, x, z);
}
S = 1, T = N, K = 2;
for(DI = 1; DI < K; DI <<= 1);
}
void update(int i)
{
for(; i ^ 1; i >>= 1)
tree[i >> 1] = t[tree[i]].min < t[tree[i ^ 1]].min ? tree[i] : tree[i ^ 1];
}
void solve()
{
int i, j, k, cnt, x, y, z;
memset(tree + 1, 0, sizeof(tree[0]) * (DO << 1));
for(i = 0; i < DO; i ++)
{
t[i].init();
tree[i + DO] = i;
}
for(i = DO - 1; i > 0; i --)
tree[i] = tree[i << 1];
t[S].Insert(0), update(S + DO);
cnt = 0;
while(t[x = tree[1]].min != INF)
{
if(x == T)
{
if(++ cnt == K)
break;
}
for(i = first[x]; i != -1; i = next[i])
if(t[v[i]].Insert(t[x].min + w[i]))
update(v[i] + DO);
t[x].Delete(), update(x + DO);
}
if(cnt == K)
printf("%d\n", t[tree[1]].min);
else
printf("-1\n");
}
int main()
{
while(scanf("%d%d", &N, &M) == 2)
{
init();
solve();
}
return 0;
}


posted on 2012-03-29 01:03  Staginner  阅读(334)  评论(0编辑  收藏  举报