题意:可乐机器人有三种行为: 停在原地,去下一个相邻的城市,自爆。它每一秒都会随机触发一种行为。现在给加里敦星球城市图,在第 0秒时可乐机器人在 1号城市,问经过了 t秒,可乐机器人的行为方案数是多少?(洛谷5789)
输入格式:第一行输入两个正整数 N,M, N表示城市个数,M表示道路个数。接下来 M 行输入 u,v,表示 u,v之间有一条双向道路。最后输入时间 t。
输出格式:输出可乐机器人的行为方案数,答案可能很大,请输出对 2017取模后的结果。
分析:设现在有一个邻接矩阵A那么Ak的意义是什么?(两个点之间若有边则A[u][v]=1)
从floyd算法的角度考虑,不难发现Ak的第i行第j列的数字含义是从i到j经过k步的路径方案总数。
在原地停留很简单,我们只要认为每个点都有一个从自己到自己的自环即可。那自爆呢?我们可以将自爆这个状态也看成一个城市,就设它为编号0。我们在邻接矩阵上从每个点都向这个点连一条边,这个点除了自己外不连其他出边。这样就满足了任何一个点随时可以自爆,且无法恢复到其他状态。最后统计答案ans=$sum_{i=0}^{n}$A[1][i]
#include<cstdio> #include<cstring> #define min(a,b) (a)<(b) ? (a):(b) int n,t,s,e,tot,u,v,w; int num[1005]; struct Node{ int dis[205][205]; Node operator *(const Node &x)const{ Node ans; memset(ans.dis,0x3f,sizeof(ans.dis)); for(int i = 1; i <= tot; ++i) for(int t = 1; t <= tot; ++t) for(int k = 1; k <= tot; ++k) ans.dis[i][t] = min(ans.dis[i][t],dis[i][k]+x.dis[k][t]); return ans; } }a,b; void quick_pow(int n){ b = a; while(n){ if(n&1) b = a*b; a = a*a; n >>= 1; } } int main(){ scanf("%d%d%d%d",&n,&t,&s,&e); memset(a.dis,0x3f,sizeof(a.dis)); for(int i = 1; i <= t; ++i){ scanf("%d%d%d",&w,&u,&v); if(!num[u]) num[u] = ++tot; if(!num[v]) num[v] = ++tot; a.dis[num[u]][num[v]] = a.dis[num[v]][num[u]] = w; } quick_pow(n-1); printf("%d",b.dis[num[s]][num[e]]); return 0; }