题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2157
题目大意: 给出有向连通图,求A到B恰好经过K个点的方案数%m
解题思路: 邻接矩阵0-1存储边edge[ ][ ]
邻接矩阵相乘,edge[i][k]*edge[k][j]当且仅当edge[i][k]和edge[k][j]同时为1,也就是同时存在这两条边时相乘才为1
定义G[i][j]m表示i到j恰好经过m条边的方案数,则方程:
G[i][j]m=ΣG[i][k]m-1*edge[k][j](1<=k<=n)
利用二进制的思想把m次计算简化成log m次运算
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INF 0x3f3f3f3f
#define MAX 110
typedef struct node{
int edge[MAX][MAX];
}matrix;
matrix map,map2,ant,temp;
int n,mm=1000;
matrix Matrix(matrix &a,matrix &b)
{
int i,j,k;
memset(temp.edge,0,sizeof(temp.edge)); //temp初始化为0
for(i=0;i<n;i++)
for(j=0;j<n;j++)
for(k=0;k<n;k++)
temp.edge[i][j]=(temp.edge[i][j]+a.edge[i][k]*b.edge[k][j]%mm); //乘积%mm
return temp;
}
int Find(int s,int e,int k) //快速幂的思想
{
while(k)
{
if(k%2)
ant=Matrix(map2,ant);
map2=Matrix(map2,map2);
k>>=1;
}
return ant.edge[s][e];
}
int main()
{
int i,j,m,t,a1,a2,s,e,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;
memset(map.edge,0,sizeof(map.edge));
for(i=0;i<m;i++)
{
scanf("%d%d",&a1,&a2);
map.edge[a1][a2]=1; //单向边
}
scanf("%d",&t);
while(t--)
{
memset(ant.edge,0,sizeof(ant.edge)); //ant初始化为单位矩阵
for(i=0;i<n;i++)
for(j=0;j<n;j++)
map2.edge[i][j]=map.edge[i][j];
for(i=0;i<n;i++)
ant.edge[i][i]=1;
scanf("%d%d%d",&s,&e,&k);
printf("%d\n",Find(s,e,k)%mm);
}
}
return 0;
}
注:原创文章,转载请注明出处