POJ 3613 Cow Relays

本文介绍了解决特定最短路径问题的一种高效算法实现。通过使用矩阵f[i][j][n]表示经过n条边从i到j的最短路径,并采用二分思想和快速幂计算技巧,显著减少了计算复杂度。文中还提到针对大规模顶点编号进行映射以优化计算过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ_3613

    这个题目我们可以用一个矩阵f[i][j][n]表示进过的边数为n的i到j的最短路,利用二分的思想就可以得到f[i][j][n]=min{f[i][k][n/2]+f[k][j][n-n/2]},这样就可以用快速幂去做了。只要先求得f[i][k][n/2],就可以利用f[i][k][n/2]求得f[k][j][n-n/2],于是一共只需要计算O(logn)个矩阵,每个矩阵是2维的,计算的时候可以用floyd。

    此外,这个题目顶点的标号范围较大,但实际上点数很少,所以可以先将各个点做一次映射。

#include<stdio.h>
#include<string.h>
#define MAXM 110
#define MAXN 1010
#define MAXD 210
#define INF 0x3f3f3f3f
int N, T, S, E, D, h[MAXN], v[MAXD], g[MAXD][MAXD], t[MAXD][MAXD];
struct Egde
{
int x, y, z;
}edge[MAXM];
struct Matrix
{
int a[MAXD][MAXD];
void init()
{
memset(a, 0x3f, sizeof(a));
}
void multiply(Matrix &m)
{
int i, j, k;
memset(t, 0x3f, sizeof(t));
for(k = 0; k < D; k ++)
for(i = 0; i < D; i ++)
for(j = 0; j < D; j ++)
if(a[i][k] + m.a[k][j] < t[i][j])
t[i][j] = a[i][k] + m.a[k][j];
memcpy(a, t, sizeof(t));
}
}one;
void init()
{
int i, j, k, x, y, z;
D = 0;
memset(h, -1, sizeof(h));
for(i = 0; i < T; i ++)
{
scanf("%d%d%d", &z, &x, &y);
edge[i].x = x, edge[i].y = y, edge[i].z = z;
h[x] = h[y] = 1;
}
for(i = 0; i < MAXN; i ++)
if(h[i] != -1)
{
h[i] = D;
v[D ++] = i;
}
one.init();
for(i = 0; i < T; i ++)
{
x = h[edge[i].x], y = h[edge[i].y], z = edge[i].z;
if(z < one.a[x][y])
one.a[x][y] = one.a[y][x] = z;
}
}
Matrix pow_mod(int n)
{
if(n == 1)
return one;
int i, j, k;
Matrix ans = pow_mod(n / 2);
ans.multiply(ans);
if(n & 1)
ans.multiply(one);
return ans;
}
void solve()
{
int i, j, k;
Matrix ans = pow_mod(N);
E = h[E], S = h[S];
printf("%d\n", ans.a[E][S]);
}
int main()
{
while(scanf("%d%d%d%d", &N, &T, &S, &E) == 4)
{
init();
solve();
}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值