HDU 2807 The Shortest Path
最短路。全源最短路,使用floyd
。
给你很多个矩阵,每个矩阵代表一个点,两点之间有一条有向边(A->C
,权值为1
)当且仅当A*B=C
(矩阵运算),其中A
,B
,C
代表不同的点。然后给很多个查询,每次问你从一个点到另一个点的最短路。
主要注意上述A
,B
,C
指代不同的点。
矩阵相乘放在第二层循环得出结果,再和第三层枚举的每个矩阵比较。
话说刚刚看了一下别的题解,居然发现还有 快速矩阵比较 这种东西,能O(n)
完成矩阵比较?。。太秀了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
using namespace std;
const int INF = 1e9;
const int MAX = 81;
int N, M, Q;
int mtx[MAX][MAX][MAX];
int d[MAX][MAX]; // 邻接矩阵
int t[MAX][MAX]; // 存储矩阵乘积的临时矩阵
void init()
{
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= N; j++)
{
if (i != j) d[i][j] = INF;
else d[i][j] = 0; // 使用邻接矩阵时这一步还是必要的,至少稳当
}
}
}
void mul(int a, int b) // a*b=c
{
int s;
for (int i = 1; i <= M; i++)
{
for (int j = 1; j <= M; j++)
{
s = 0;
for (int k = 1; k <= M; k++)
{
s += mtx[a][i][k] * mtx[b][k][j];
}
t[i][j] = s;
}
}
}
void floyd()
{
for (int k = 1; k <= N; k++)
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
{
if(d[i][k] != INF && d[k][j] != INF && d[i][k] + d[k][j] < d[i][j])
{
d[i][j] = d[i][k] + d[k][j];
}
}
}
bool equal(int x)
{
for (int i = 1; i <= M; i++)
{
for (int j = 1; j <= M; j++)
{
if (mtx[x][i][j] != t[i][j]) return false;
}
}
return true;
}
int main()
{
int a, b;
for (; ~scanf("%d%d", &N, &M);)
{
if (!N && !M) break;
init();
for (int i = 1; i <= N; i++)
for (int j = 1; j <= M; j++)
for (int k = 1; k <= M; k++)
scanf("%d", &mtx[i][j][k]);
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= N; j++)
{
if (i == j) continue; // 人家题目中说了A,B,C是三个城市,不能指代相同
mul(i, j); // 把矩阵乘法放在第二层进行,不要放到第三层
for (int k = 1; k <= N; k++)
{
if (k == i || d[i][k] == 1) continue;
if (k == j) continue; // 没加这个就 WA,看来里面有单位矩阵(A)
// 按照题目规矩来,人家说了A,B,C是三个城市,这就意味着不能指代相同
if (equal(k))
d[i][k] = 1;
}
}
}
floyd();
scanf("%d", &Q);
for (; Q--;)
{
scanf("%d%d", &a, &b);
if (d[a][b] == INF) printf("Sorry\n");
else printf("%d\n", d[a][b]);
}
}
return 0;
}