HDU - 2807The Shortest Path(矩阵相乘+Floyd)


Time Limit: 2000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u

Status

Description

There are N cities in the country. Each city is represent by a matrix size of M*M. If city A, B and C satisfy that A*B = C, we say that there is a road from A to C with distance 1 (but that does not means there is a road from C to A).
Now the king of the country wants to ask me some problems, in the format:
Is there is a road from city X to Y?
I have to answer the questions quickly, can you help me?
 

Input

Each test case contains a single integer N, M, indicating the number of cities in the country and the size of each city. The next following N blocks each block stands for a matrix size of M*M. Then a integer K means the number of questions the king will ask, the following K lines each contains two integers X, Y(1-based).The input is terminated by a set starting with N = M = 0. All integers are in the range [0, 80].
 

Output

For each test case, you should output one line for each question the king asked, if there is a road from city X to Y? Output the shortest distance from X to Y. If not, output "Sorry".
 

Sample Input

    
    
3 2 1 1 2 2 1 1 1 1 2 2 4 4 1 1 3 3 2 1 1 2 2 1 1 1 1 2 2 4 3 1 1 3 0 0
 

Sample Output

    
    
1 Sorry
 

Source

HDU 2009-4 Programming Contest


题意:有 n 个矩阵,大小均为 m*m,  如果存在 A*B = C, 则A到C存在路径,且长度为1,询问 k 次,某两个矩阵是否存在最短路,有则输出最短路,没有输出 Sorry。数据均不超过 80

思路:用朴素矩阵乘法造图,再用 Floyd 求最短路。


<span style="font-size:18px;">#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;

const double PI = acos(-1.0);
const double e = 2.718281828459;
const double eps = 1e-8;
const int MAXN = 82;
const int INF = 1<<29;
struct Matrix {
    int n, m;
    int a[MAXN][MAXN];
    void clear() {
        n = m = 0;
        memset(a, 0, sizeof(a));
    }
} M[MAXN];
int n, m, k;
int w[MAXN][MAXN];

void Multi(Matrix a, Matrix b, Matrix &t) {
    t.clear();
    t.n = t.m = a.n;
    for(int i = 1; i <= t.n; i++) {
        for(int j = 1; j <= t.n; j++) {
            for(int k = 1; k <= t.n; k++)
                t.a[i][j] += a.a[i][k]*b.a[k][j];
        }
    }
}

int cmp(Matrix a, Matrix b) {
    for(int i = 1; i <= a.n; i++) {
        for(int j = 1; j <= a.n; j++) {
            if(a.a[i][j] != b.a[i][j])
                return 0;
        }
    }
    return 1;
}

void Floyd() {
    for(int k = 1; k <= n; k++) {
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++)
                if(w[i][j] > w[i][k]+w[k][j])
                    w[i][j] = w[i][k]+w[k][j];
        }
    }
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int u, v;
    while(cin>>n>>m) {
        if(!n || !m)
            break;
        for(int i = 1; i <= n; i++)
            M[i].clear();
        for(int i = 1; i <= n; i++) {
            M[i].n = M[i].m = m;
            for(int j = 1; j <= m; j++)
                for(int k = 1; k <= m; k++) {
                    scanf("%d", &M[i].a[j][k]);
                }
        }
        scanf("%d", &k);
        Matrix t;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++)
                w[i][j] = (i==j)?0:INF;
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(i == j)
                    continue;
                Multi(M[i], M[j], t);
                for(int k = 1; k <= n; k++) {
                    if(i==k || j==k)
                        continue;
                    if(cmp(t, M[k])) {
                        //printf("%d %d %d\n", i, j, k);
                        w[i][k] = 1;
                    }
                }
            }
        }
        Floyd();
        while(k--) {
            scanf("%d %d", &u, &v);
            if(w[u][v] < INF)
                printf("%d\n", w[u][v]);
            else
                printf("Sorry\n");
        }
    }
    return 0;
}

</span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值