题意
给了一个路径的定义,每次严格+1的走,能走的必须要走。求这样的路径长度大于4的有多少个。
思路
BFS搜索,但有个问题是如果两条路,有很大一部分是重复的,应该只走一遍。
用入度出度,in,out记录,如果入度为0,则是起点,如果出度为0,则是终点。所有的起点入队,BFS。每次到达一个点,先让该点的入度减一,如果变为0,则入队。这样如果一个点有多个入度,就会只走一次。
用dp记录每个点的信息,到达该点的路径长度分别为1,2,3,大于等于4的路径个数。状态转移的时候,长度1变为长度2,长度2变为长度3,长度3变为长度4。但是dp[4][x][y]的含义是大于等于4的路径个数,所以大于等于4的加上1还是大于等于4,也要加上去。
所以是想到了重复的路径要只走一次,用数组记录信息,但是不知道怎么处理。
想想入度出度,dp数组情况都开就完事了,QAQ
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int N = 1010;
const int mod = 1e9+7;
struct node
{
int x,y;
node(){}
node(int xx,int yy):x(xx),y(yy){}
};
int m,n;
int a[N][N],dp[5][N][N],in[N][N],out[N][N];
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
bool valid(int x,int y)
{
if(x<1||y<1||x>m||y>n) return false;
else return true;
}
void Add(int i,int j,int x,int y)
{
dp[2][x][y] = (dp[2][x][y] + dp[1][i][j])%mod;
dp[3][x][y] = (dp[3][x][y] + dp[2][i][j])%mod;
dp[4][x][y] = (dp[4][x][y] + dp[3][i][j] + dp[4][i][j])%mod;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
}
}
queue <node> Q;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
for(int k=0;k<4;k++){
int tx = i + dir[k][0];
int ty = j + dir[k][1];
if(valid(tx,ty)==0) continue;
if(a[tx][ty]==a[i][j]+1) out[i][j]++;
if(a[tx][ty]==a[i][j]-1) in[i][j]++;
}
if(in[i][j]==0) {Q.push(node(i,j));dp[1][i][j]++;}
}
}
node p;
while(!Q.empty())
{
p = Q.front(); Q.pop();
for(int k=0;k<4;k++){
int tx = p.x + dir[k][0];
int ty = p.y + dir[k][1];
if(valid(tx,ty)==0) continue;
if(a[tx][ty]!=a[p.x][p.y]+1) continue;
Add(p.x,p.y,tx,ty);
in[tx][ty]--;
if(in[tx][ty]==0) Q.push(node(tx,ty));
}
}
int ans = 0;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(out[i][j]==0) ans = (ans + dp[4][i][j])%mod;
}
}
printf("%d",ans);
return 0;
}