题目链接:Digital Path
路径数量,我们可以想到每次暴力bfs往附近转移。
但是肯定TLE,然后这道题会有路径覆盖的问题,有些路径会被覆盖掉,所以所有有效的路径肯定是从入度为0的点开始。
然后也有许多路径会有交集,所以每次暴力从入度为0的点开始bfs是不行的,然后其实我们可以想到,这个和拓扑排序十分像,于是我们用拓扑排序来状态转移,当这个点入度为0时才加入队列,就保证了每个点入队一次,出队一次的复杂度。
我们用 dp[i][j][k]来表示当前在位置 (i,j),到达长度为k的路径数量,大于等于4算在一起。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e3+10,p=1e9+7;
const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int n,m,g[N][N],in[N][N],out[N][N],dp[N][N][5],res;
void top_sort(){
queue<pair<int,int> > q;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!in[i][j]){
q.push({i,j}); dp[i][j][1]=1;
}
while(q.size()){
int ux=q.front().first,uy=q.front().second; q.pop();
for(int i=0;i<4;i++){
int tx=ux+dx[i],ty=uy+dy[i];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&g[tx][ty]==g[ux][uy]+1){
dp[tx][ty][2]=(dp[tx][ty][2]+dp[ux][uy][1])%p;
dp[tx][ty][3]=(dp[tx][ty][3]+dp[ux][uy][2])%p;
dp[tx][ty][4]=(dp[tx][ty][4]+dp[ux][uy][3]+dp[ux][uy][4])%p;
if(--in[tx][ty]==0) q.push({tx,ty});
}
}
}
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%lld",&g[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++){
int tx=i+dx[k],ty=j+dy[k];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m){
if(g[tx][ty]==g[i][j]+1) out[i][j]++;
if(g[tx][ty]==g[i][j]-1) in[i][j]++;
}
}
top_sort();
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!out[i][j]){
res=(res+dp[i][j][4])%p;
}
cout<<res<<endl;
return 0;
}