您的位置:首页 > 其它

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

2016-06-07 13:11 423 查看

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hdu 2807 杭电 2807