hdu 2807 The Shortest Path【暴力/矩阵判等优化+Floyd】

来源:互联网 发布:佛山市禅城区广电网络 编辑:程序博客网 时间:2024/09/21 11:23

The Shortest Path

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3042    Accepted Submission(s): 995

Problem 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有一条有向边。 对于那么些个询问,如果这两个节点之间有路想通,输出最小路径,否则输出Sorry。


思路:

1、对于之后询问部分的操作,每次询问都做一次单源最短路显然是有点多余的,而且N最大也就80,我们不妨在这里求最短路的时候使用Floyd算法求其最短路,这样对于每个查询直接输出即可。

2、对于这个题来说,最难受的一个点就是如果两层for枚举I,J点对,然后求其矩阵乘法,然后再从其他矩阵里边找是否和当前乘法之后求得的矩阵相等,显然最差需要N^2*M^3来做这个题。如果N,M都是80的话,显然会超时,但是捏,后台数据一定是放宽了条件,暴力代码AC了0.0.


这里先上一下暴力AC代码:

1200+ms

#include<stdio.h>#include<string.h>#include<iostream>using namespace std;typedef struct Matrix{    int mat[85][85];} matrix;int n,m;int map[85][85];matrix a[85];int min(int a,int b){    if(a>b)return b;    else return a;}Matrix matrix_mul(matrix a,matrix b){    matrix c;    memset(c.mat,0,sizeof(c.mat));    int i,j,k;    for(int i=0; i<m; i++)    {        for(int j=0; j<m; j++)        {            for(int k=0; k<m; k++)            {                c.mat[i][j]+=a.mat[i][k]*b.mat[k][j];            }        }    }    return c;}int judge(matrix a,matrix b){    for(int i=0; i<m; i++)    {        for(int j=0; j<m; j++)        {            if(a.mat[i][j]!=b.mat[i][j])return 0;        }    }    return 1;}void Floyd(){    for(int i=0; i<n; i++)    {        for(int j=0; j<n; j++)        {            for(int k=0; k<n; k++)            {                map[j][k]=min(map[j][k],map[j][i]+map[i][k]);            }        }    }}void getmap(){    for(int i=0; i<n; i++)    {        for(int j=0; j<n; j++)        {            if(i==j)continue;            matrix tmp;            tmp=matrix_mul(a[i],a[j]);            for(int k=0; k<n; k++)            {                if(k==i||k==j)continue;                if(judge(tmp,a[k])==1)                {                    map[i][k]=1;                }            }        }    }}int main(){    while(~scanf("%d%d",&n,&m))    {        if(n==0&&m==0)break;        for(int i=0; i<n; i++)        {            for(int j=0; j<m; j++)            {                for(int k=0; k<m; k++)                {                    scanf("%d",&a[i].mat[j][k]);                }            }        }        for(int i=0; i<n; i++)        {            for(int j=0; j<n; j++)            {                map[i][j]=0x3f3f3f3f;            }        }        getmap();        Floyd();        int q;        scanf("%d",&q);        while(q--)        {            int x,y;            scanf("%d%d",&x,&y);            x--;            y--;            if(map[x][y]<0x3f3f3f3f)            {                printf("%d\n",map[x][y]);            }            else printf("Sorry\n");        }    }    return 0;}


3、在这里,其实我们可以对于矩阵判等进行优化。我们知道,如果直接求当前题情况下两个矩阵的乘法,那么需要M^3来计算这个乘法之后的矩阵,其实我们不妨这样来优化:

假设我们要判断:A*B==C,我们其实可以这样加以判断:D*A*B==D*C;可能读者一下子笑了,这尼玛能优化?明明增加了乘法操作好伐。其实不然,如果D也是M*M规格的,显然是多余了,不过假如我们让D的规模是1*M,这样显然需要的操作是1*M*M+1*M*M*1*M*M。实现了优化,并没有增加乘法的操作。


优化算法之后的AC代码:
400+ms

#include<stdio.h>#include<string.h>#include<iostream>using namespace std;typedef struct Matrix{    int mat[85][85];} matrix;int n,m;int map[85][85];matrix a[85];void Floyd(){    for(int i=0; i<n; i++)    {        for(int j=0; j<n; j++)        {            for(int k=0; k<n; k++)            {                map[j][k]=min(map[j][k],map[j][i]+map[i][k]);            }        }    }}void getmap(){    int tmp[85];    int tmp2[85];    int c[85];    for(int i=0;i<n;i++)    {        for(int j=0;j<n;j++)        {            if(i==j)continue;            for(int k=0;k<m;k++)tmp[k]=0;            for(int k=0;k<m;k++)c[k]=0;            for(int k=0;k<m;k++)            {                for(int l=0;l<m;l++)                {                    tmp[k]+=1*a[i].mat[k][l];                }            }            for(int k=0;k<m;k++)            {                for(int l=0;l<m;l++)                {                    c[k]+=tmp[k]*a[j].mat[k][l];                }            }            for(int k=0;k<n;k++)            {                if(k==i||k==j)continue;                for(int x=0;x<m;x++)tmp2[x]=0;                for(int x=0;x<m;x++)                {                    for(int y=0;y<m;y++)                    {                        tmp2[x]+=1*a[k].mat[x][y];                    }                }                int flag=1;                for(int x=0;x<m;x++)                {                    if(c[x]!=tmp2[x])                    flag=0;                }                if(flag==1)                {                    map[i][k]=1;                }            }        }    }}int main(){    while(~scanf("%d%d",&n,&m))    {        if(n==0&&m==0)break;        for(int i=0; i<n; i++)        {            for(int j=0; j<m; j++)            {                for(int k=0; k<m; k++)                {                    scanf("%d",&a[i].mat[j][k]);                }            }        }        for(int i=0; i<n; i++)        {            for(int j=0; j<n; j++)            {                map[i][j]=0x3f3f3f3f;            }        }        getmap();        Floyd();        int q;        scanf("%d",&q);        while(q--)        {            int x,y;            scanf("%d%d",&x,&y);            x--;            y--;            if(map[x][y]<0x3f3f3f3f)            {                printf("%d\n",map[x][y]);            }            else printf("Sorry\n");        }    }    return 0;}






0 0
原创粉丝点击