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;
}