一本通1647迷路
1647:迷路
时间限制: 1000 ms 内存限制: 524288 KB【题目描述】
原题来自:SCOI 2009
Windy 在有向图中迷路了。 该有向图有 N 个节点,Windy 从节点 0 出发,他必须恰好在 T 时刻到达节点 N−1。
现在给出该有向图,你能告诉 Windy 总共有多少种不同的路径吗?
注意:Windy 不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
【输入】
第一行包含两个整数,N,T;
接下来有 N 行,每行一个长度为 N 的字符串。第 i 行第 j 列为 0 表示从节点 i 到节点 j 没有边,为 1 到 9 表示从节点 i 到节点 j 需要耗费的时间。
【输出】
包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以 2009 的余数。
【输入样例】
2 2
11
00
【输出样例】
1
【提示】
样例说明 1
0→0→1
样例输入 2
5 30
12045
07105
47805
12024
12345
样例输出 2
852
数据范围与提示:
对于 30% 的数据,满足 2≤N≤5,1≤T≤30;
对于 100% 的数据,满足 2≤N≤10,1≤T≤109。
sol:对于样例1其实是一种特殊情况(边权只有0/1)
思考如何处理这种情况
令anst,i,j表示恰好用 t 的时间,从 i 到 j 的方案数,很显然的转移anst,i,j=anst-1,i,k*ans1,k,j,其实ans1,k,j就是Disk,j,
暴力的实现就是转移T次
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const int N=15; int n,Time; int Dis[N][N]; int ans[35][N][N]; int main() { int i,j,k; R(n); R(Time); for(i=1;i<=n;i++) for(j=1;j<=n;j++) { char ch=' '; while(!isdigit(ch)) ch=getchar(); Dis[i][j]=ch-'0'; if(Dis[i][j]) ans[1][i][j]=1; } for(int t=2;t<=Time;t++) { for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=1;k<=n;k++) { ans[t][i][j]+=ans[t-1][i][k]*Dis[k][j]; } } Wl(ans[Time][1][n]); return 0; }
对于边权不是0,1的点,似乎一脸生无可恋的样子,因为边权都很小,所以把每个点拆成9个点,表示从 i 点出发走距离1,2,~~,9,
这样就能保证边权为0,1了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const ll Mod=2009; const int N=95; int n,Time; int Dis[N][N]; ll ans[35][N][N]; ll Pic[N][N]; inline void Ad(ll &x,ll y) { x+=y; x-=(x>=Mod)?Mod:0; return; } inline void Build_Pic() { int i,j; for(i=1;i<=n;i++) { for(j=1;j<=8;j++) Pic[(i-1)*9+j][(i-1)*9+j+1]=1; for(j=1;j<=n;j++) if(Dis[i][j]) { Pic[(i-1)*9+Dis[i][j]][(j-1)*9+1]=1; } } n*=9; // for(i=1;i<=n;i++,puts("")) // { // for(j=1;j<=n;j++) W(Pic[i][j]); // } return; } char S[15]; int main() { // freopen("road.in","r",stdin); // freopen("test.out","w",stdout); int i,j,k; R(n); R(Time); for(i=1;i<=n;i++) { scanf("%s",S+1); for(j=1;j<=n;j++) Dis[i][j]=S[j]-'0'; } Build_Pic(); //暴力 for(i=1;i<=n;i++) for(j=1;j<=n;j++) { ans[1][i][j]=Pic[i][j]; } for(int t=2;t<=Time;t++) { for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=1;k<=n;k++) { ans[t][i][j]+=ans[t-1][i][k]*Pic[k][j]; ans[t][i][j]%=Mod; } } Wl(ans[Time][1][n-8]); return 0; } /* input 5 30 33454 43629 41539 88547 44006 output 343 input 5 30 12045 07105 47805 12024 12345 output 852 */
之后加上矩阵快速幂优化就可以潇洒的水过此题了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const ll Mod=2009; const int N=95; int n,Time; int Dis[N][N]; ll ans[N][N],a[N][N],c[N][N]; ll Pic[N][N]; inline void Ad(ll &X,ll Y) { X+=Y; X-=(X>=Mod)?Mod:0; return; } inline void Build_Pic() { int i,j; for(i=1;i<=n;i++) { for(j=1;j<=8;j++) Pic[(i-1)*9+j][(i-1)*9+j+1]=1; for(j=1;j<=n;j++) if(Dis[i][j]) { Pic[(i-1)*9+Dis[i][j]][(j-1)*9+1]=1; } } n*=9; // for(i=1;i<=n;i++,puts("")) // { // for(j=1;j<=n;j++) W(Pic[i][j]); // } return; } char S[15]; int main() { // freopen("road.in","r",stdin); // freopen("my.out","w",stdout); int i,j,k; R(n); R(Time); for(i=1;i<=n;i++) { scanf("%s",S+1); for(j=1;j<=n;j++) Dis[i][j]=S[j]-'0'; } Build_Pic(); for(i=1;i<=n;i++) ans[i][i]=1; memmove(a,Pic,sizeof a); int tt=Time; // printf("n=%d\n",n); while(tt) { if(tt&1) { memset(c,0,sizeof c); for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=1;k<=n;k++) { Ad(c[i][j],ans[i][k]*a[k][j]%Mod); } memmove(ans,c,sizeof ans); } memset(c,0,sizeof c); for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=1;k<=n;k++) { Ad(c[i][j],a[i][k]*a[k][j]%Mod); } memmove(a,c,sizeof a); tt>>=1; } Wl(ans[1][n-8]); return 0; } /* input 2 2 11 00 output 1 input 5 30 33454 43629 41539 88547 44006 output 343 input 5 30 12045 07105 47805 12024 12345 output 852 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!