矩阵十题(8)

经典题目8

hdu  2157  How many ways??

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2157

题目大意:给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值
把 给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就 等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。同理,如果要求经过k步的 路径数,我们只需要二分求出A^k即可。

代码如下:

 1 #include<stdio.h>

 2 #include<string.h>

 3 #define N 21

 4 #define M 1000

 5 struct Matrix

 6 {

 7     int edge[N][N];

 8 }map,res,tmp,map2;

 9 int n,m;

10 Matrix mul(Matrix x,Matrix y)  //矩阵连乘

11 {

12     int i,j,k;

13     memset(tmp.edge,0,sizeof(tmp.edge));

14     for(i=0;i<n;i++)

15         for(j=0;j<n;j++)

16             for(k=0;k<n;k++)

17             {

18                 tmp.edge[i][j]+=(x.edge[i][k]*y.edge[k][j])%M;

19                 tmp.edge[i][j]%=M;

20             }

21     return tmp;

22 }

23 void quickpow(int k)   //二进制思想

24 {

25     int i;

26     memset(res.edge,0,sizeof(res.edge));

27     for(i=0;i<n;i++)   //初始化为单位矩阵

28             res.edge[i][i]=1;

29     while(k)

30     {

31         if(k&1)

32             res=mul(res,map2);

33         map2=mul(map2,map2);

34         k>>=1;

35     }

36 }

37 int main()

38 {

39     int i,a,b,k,j,s,e,t;

40     while(scanf("%d%d",&n,&m)!=EOF)

41     {

42         if(n==0&&m==0)

43             break;

44         memset(map.edge,0,sizeof(map.edge));

45         for(i=0;i<m;i++)

46         {

47             scanf("%d%d",&a,&b);

48             map.edge[a][b]=1;

49         }

50         scanf("%d",&t);

51         while(t--)

52         {

53             scanf("%d%d%d",&s,&e,&k);

54             for(i=0;i<n;i++)

55                 for(j=0;j<n;j++)

56                     map2.edge[i][j]=map.edge[i][j];

57             quickpow(k);

58             printf("%d\n",res.edge[s][e]%M);

59         }

60     }

61     return 0;

62 }
View Code

 

poj  3613  Cow Relays

题目链接:    http://poj.org/problem?id=3613

题目大意:   给出一张无向连通图,求S到E经过k条边的最短路。

解题思路:    利用递推的思路,先算出经过一条边的最短路,再算两条边......k-1条边,k条边的最短路

                  先看一下Floyd的核心思想: edge[i][j]=min(edge[i][j],edge[i][k]+edge[k][j])

                  i到j的最短路是i到j的直接路径或者经过k点的间接路径,但是矩阵的更新总是受到上一次更新的影响

                  如果每次的更新都存进新矩阵,那么edge[i][k]+edge[k][j]是不是表示只经过三个点两条边的路径呢?

                  min(edge[i][j],edge[i][k]+edge[k][j])就表示只经过三个点两条边的最短路

                  方程:F[i][j]m=min(F[i][k]m-1+G[k][j]) {1kn,   m>1}

                  经过k条边的最短路,那么我们只需要把这个代码重复运行k次

while(k)  

{  

   res=mul(map,ant);  

   k--;  

}

这样显然答案是正确的,但是时间复杂度太高O(k*n^3),利用二进制的思想可以把时间复杂度降到O(logK*n^3)

另外,存储边的邻接矩阵map.edge[i][i]不能初始化为0,为0时每次Floyd都会考虑走i--->i这条边,实际上这条边是不存在的

代码如下:

 1 //k步最短路

 2  #include<stdio.h>

 3  #include<string.h>

 4  #define INF 0x3f3f3f3f

 5  #define N 101

 6  struct Matrix

 7  {

 8      int edge[N][N];

 9  }map,tmp,res;

10  int n,f[N*10];

11  Matrix mul(Matrix x,Matrix y)    //floyd

12  {

13      memset(tmp.edge,INF,sizeof(tmp.edge));

14      int i,j,k;

15      for(i=1;i<=n;i++)

16          for(j=1;j<=n;j++)

17              for(k=1;k<=n;k++)

18                  if(tmp.edge[i][j]>x.edge[i][k]+y.edge[k][j])

19                      tmp.edge[i][j]=x.edge[i][k]+y.edge[k][j];

20      return tmp;

21  }

22  void quickpow(int k)

23  {

24      int i;

25      memset(res.edge,INF,sizeof(res.edge));

26      for(i=1;i<=n;i++)

27          res.edge[i][i]=0;

28      while(k)    //二进制思想

29      {

30          if(k&1)

31              res=mul(res,map);

32          map=mul(map,map);

33          k>>=1;

34      }

35  }

36  int main()

37  {

38      int i,k,t,s,e,len,u,v;

39      scanf("%d%d%d%d",&k,&t,&s,&e);

40      memset(map.edge,INF,sizeof(map.edge));

41      memset(f,-1,sizeof(f));

42      int num=0;

43      for(i=0;i<t;i++)

44      {

45          scanf("%d%d%d",&len,&u,&v);

46          if(f[u]==-1)    //离散化

47              f[u]=++num;

48          if(f[v]==-1)    //离散化

49              f[v]=++num;

50          map.edge[f[u]][f[v]]=map.edge[f[v]][f[u]]=len;

51      }

52      n=num;

53      quickpow(k);  

54      printf("%d\n",res.edge[f[s]][f[e]]);

55      return 0;

56  }
View Code

 

 

 

你可能感兴趣的:(矩阵)