题意:求A经过K个点到B方案数
方法一:
1个0 1 的矩阵 Aa[i][j] = 1 表示i 到 j可达 或者说 i 到 j 有1条路 或者说i到j经过一个点的方案数 路可以重复走
而A2 = A* A
a[i][j] 的含义是
从i到j经过2个点的方案数
A的k次方 A[i,j]代表 i到j走k步的方案有a[i][j]
矩阵乘法的定义居然和这个模型如此契合,佩服,所以要非常熟悉矩阵乘法的具体步骤才能在这个题目中抽象出矩阵乘法可以正好实现两个定点间的所有可能情况
方法二:
动态规划的思路,状态是dp[c][u] 从起始点s到u点经过c条边的所有方法数,这种把起点看出固定,把终点看成状态之一的动态规划思路在最短路模型中已经多见。在dp(c,u)这个状态后的决策是:u,v之间有有向边,那么可以向dp(c+1,v)的状态转移。
矩阵快速幂:
//1100 KB 78 ms
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000
struct mat{
int a[25][25];
void ini(){
memset(a,0,sizeof(a));
}
};
int n,m;
mat mapp;
int st,ed,c;
mat mul(mat &m1,mat &m2){
mat ans;
ans.ini();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(m1.a[i][j])
for(int k=1;k<=n;k++)
ans.a[i][k]=(ans.a[i][k]+m1.a[i][j]*m2.a[j][k])%mod;
return ans;
}
int quickmul(mat m,int c){
mat ans;
ans.ini();
for(int i=1;i<=n;i++) ans.a[i][i]=1;
while(c){
if(c&1) ans=mul(ans,m);
m=mul(m,m);
c>>=1;
}
return ans.a[st][ed];
}
int main(){
while(scanf("%d%d",&n,&m),n+m){
mapp.ini();
while(m--){
int u,v;
scanf("%d%d",&u,&v);
mapp.a[++u][++v]=1;
}
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&st,&ed,&c);
st++;ed++;
printf("%d\n",quickmul(mapp,c));
}
}
return 0;
}
动态规划:
//15MS 1092K
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
#define mod 1000
int dp[25][25];
bool mapp[25][25];
int main(){
int n,m;
while(scanf("%d%d",&n,&m),m+n){
memset(mapp,0,sizeof(mapp));
while(m--){
int u,v;
scanf("%d%d",&u,&v);
mapp[++u][++v]=1;
}
int t;
scanf("%d",&t);
while(t--){
memset(dp,0,sizeof(dp));
int st,ed,k;
scanf("%d%d%d",&st,&ed,&k);
st++;ed++;
dp[0][st]=1;
for(int c=1;c<=k;c++)
for(int u=1;u<=n;u++)
for(int v=1;v<=n;v++){
if(mapp[u][v]) dp[c][v]=(dp[c][v]+dp[c-1][u])%mod;
}
printf("%d\n",dp[k][ed]);
}
}
return 0;
}