HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径
标签:void ons char strong 路径 tin 哪些 知识 题目
HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径
一行,表示答案。
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2
4
题解
考试的时候想得比较粗略,一开始当然是暴力深搜,也知道这种方案数还取模的题不可能深搜出正解,但还是先打了一通,没费什么力气就出了样例。之后开始想正解,感觉或许应该把环收缩一下,但是环环相扣环环重叠不知道应该怎么处理,最后还是把深搜交上去了。
正解是矩阵优化dp(但总感觉它其实说不上是dp),比如矩阵G[i,j]的k次方中的g(a,b)可以表示从a点到b点经过k条边的方案数,本题因为对于边有特殊的要求(不立刻反向)所以把边放进矩阵,G[i,j]为1表示从i到j有一条边,这里的边是分方向的,双向建边就会有2*m条。tot矩阵(其实只有一行)表示从起点有哪些边出来。tot乘上G[i,j]的k-1次方(注意顺序,矩阵乘法不满足交换律),把得到的一行结果矩阵中有边到终点的位加和,得到的结果即为答案。
刚开始觉得矩阵非常抽象,虽然自己在课下学过很多数学书上的理论知识但还是不会用,不过这道题让我明白矩阵也是有明确含义的(加速矩阵除外),本质上还是要理解算法每一步的目的。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m,t,a,b,temp; const int md=45989; int dis[125][125]={0},tot[2][125]={0},ans[125][125]={0}; inline int r() { int jg=0,jk=0; jk=getchar()-‘0‘; if(jk>=0&&jk<=9) jg+=jk; jk=getchar()-‘0‘; while(jk>=0&&jk<=9) { jg*=10; jg+=jk; jk=getchar()-‘0‘; } return jg; } int h[25],e; struct B { int u,v,ne; }bi[125]; void add(int x,int y) { bi[e].u=x; bi[e].v=y; bi[e].ne=h[x]; h[x]=e++; } int jg[125][125]; void jc(int cs1[][125],int cs2[][125]) { memset(jg,0,sizeof(jg)); for(int i=0;i<temp;i++) for(int j=0;j<temp;j++) for(int k=0;k<temp;k++) jg[i][j]+=(cs1[i][k]*cs2[k][j])%md; for(int i=0;i<temp;i++) for(int j=0;j<temp;j++) cs1[i][j]=jg[i][j]%md; } void init() { n=r(); m=r(); t=r(); a=r(); b=r(); temp=2*m; memset(h,-1,sizeof(h)); int a1,a2; for(int i=0;i<m;i++) { a1=r(); a2=r(); add(a1,a2); add(a2,a1); } for(int i=0;i<n;i++) for(int j=h[i];j!=-1;j=bi[j].ne) for(int k=h[bi[j].v];k!=-1;k=bi[k].ne) { if(((k&1)&&k==j+1)||((j&1)&&j==k+1)) continue; dis[j][k]=1; } for(int i=h[a];i!=-1;i=bi[i].ne) tot[0][i]=1; } int main() { init(); for(int i=0;i<temp;i++) ans[i][i]=1; t--; while(t) { if(t&1) jc(ans,dis); t>>=1; jc(dis,dis); } jc(tot,ans); int res=0; for(int i=h[b];i!=-1;i=bi[i].ne) { if(i&1) res+=tot[0][i-1]; else res+=tot[0][i+1]; } printf("%d",res%md); return 0; }
标签:void ons char strong 路径 tin 哪些 知识 题目
原文地址:http://www.cnblogs.com/moyiii-/p/7182944.html