Zhe the bully, is condemned by all kinds of evil, like bullying those who are weaker. His teammates have been mistreated for a long time. Finally, they decided not to put up with their buddy any more and flee to Digital Village, with the bully in hot pursuit. Due to difficult terrain and a considerable amount of Digital Paths staggered, they can’t be easily arrested.
Getting familiar with the terrain as soon as possible is important for these innocents to escape the threat of bullying. All they need now is to count the number of Digital Paths in Digital Village.
To simplify the problem, Digital Village is abstracted into a grid with nn rows and mm columns filled by integers. A Digital Path is a continuous walk in the grid satisfying the following conditions:
Here we have some examples.
The path in Figure 1 is invalid because its length is less than 44.
The path in Figure 2 is invalid because it is not continuous.
The path in Figure 3 is invalid because it can be extended further.
The path in Figure 4 is also invalid because values in the path are not strictly increased by one.
Digital Paths may partially overlap. In Figure 5, there are 4 Digital Paths marked by different colours.
Input
The first line contains two positive integers n and m (1≤n,m≤1000) describing the size of the grid.
Each of the next nn lines contains mm integers, the jj-th of which, denoted by ai,j (−107≤ai,j≤107), represents the value of the box in the ii-th row and the jj-th column.
Output
Output the number of Digital Paths modulo (10^9+7).
样例输入1
3 5
1 2 3 8 7
-1 -1 4 5 6
1 2 3 8 7
样例输出1
4
样例输入2
4 4
1 2 3 4
2 3 4 3
3 4 3 2
4 3 2 1
样例输出2
16
n×m的矩阵,找寻最长路径的数目,路径长度>=4,并且路径中的数值严格增加1,得到结果 mod 1e9 + 7。
有用拓扑+dpAC的
我这里用的是记忆化搜素+dp。
首先定义一下结构体:
struct node{
ll a,b,c,d;
bool flag;
}dp[maxn][maxn];
然后三个判断函数:
bool judge(int x,int y) //判断是否出界
{
if(x<1||y<1||x>n||y>m)
return false;
return true;
}
bool vis1(int i,int j) //判断是否可以向外移一个点
{
if(i-1>=1&&p[i-1][j]-p[i][j]==1) return true;
if(i+1<=n&&p[i+1][j]-p[i][j]==1) return true;
if(j-1>=1&&p[i][j-1]-p[i][j]==1) return true;
if(j+1<=m&&p[i][j+1]-p[i][j]==1) return true;
return false;
}
//判断是否可以由四周向该点移动也就是判断该点是否是最大路径的起点
bool vis2(int i,int j)
{
if(i-1>=1&&p[i][j]-p[i-1][j]==1) return false;
if(i+1<=n&&p[i][j]-p[i+1][j]==1) return false;
if(j-1>=1&&p[i][j]-p[i][j-1]==1) return false;
if(j+1<=m&&p[i][j]-p[i][j+1]==1) return false;
return true;
}
我们先更新结构体里的 a,两层 for + vis1
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(vis1(i,j)) dp[i][j].a = 0;
else dp[i][j].a = 1;
}
}
然后记忆化搜索全部矩阵
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
DFS(i,j);
}
}
node DFS(int i,int j)
{
if(dp[i][j].flag) return dp[i][j];
dp[i][j].flag = true;
for(int k=0;k<4;k++){
int nx = i + mx[k];
int ny = j + my[k];
if(judge(nx,ny)&&p[nx][ny]-p[i][j]==1){
node nxt = DFS(nx,ny);
dp[i][j].b += nxt.a;
dp[i][j].b %= mod;
dp[i][j].c += nxt.b;
dp[i][j].c %= mod;
dp[i][j].d += (nxt.c+nxt.d);
dp[i][j].d %= mod;
}
}
return dp[i][j];
}
然后就,遍历矩阵,+d了,这里要注意,为了避免重复,我们应该只加路径起点的d,也就是要用 vis2 函数判断一下。
ll ans = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(vis2(i,j)){
ans = (ans+dp[i][j].d) % mod;
}
}
}
AC代码:
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1010;
const int maxx = 1010;
struct node{
ll a,b,c,d;
bool flag;
}dp[maxn][maxn];
int n,m;
int p[maxn][maxn];
int mx[4]={1,-1,0,0};
int my[4]={0,0,1,-1};
bool judge(int x,int y)
{
if(x<1||y<1||x>n||y>m)
return false;
return true;
}
bool vis1(int i,int j)
{
if(i-1>=1&&p[i-1][j]-p[i][j]==1) return true;
if(i+1<=n&&p[i+1][j]-p[i][j]==1) return true;
if(j-1>=1&&p[i][j-1]-p[i][j]==1) return true;
if(j+1<=m&&p[i][j+1]-p[i][j]==1) return true;
return false;
}
bool vis2(int i,int j)
{
if(i-1>=1&&p[i][j]-p[i-1][j]==1) return false;
if(i+1<=n&&p[i][j]-p[i+1][j]==1) return false;
if(j-1>=1&&p[i][j]-p[i][j-1]==1) return false;
if(j+1<=m&&p[i][j]-p[i][j+1]==1) return false;
return true;
}
node DFS(int i,int j)
{
if(dp[i][j].flag) return dp[i][j];
dp[i][j].flag = true;
for(int k=0;k<4;k++){
int nx = i + mx[k];
int ny = j + my[k];
if(judge(nx,ny)&&p[nx][ny]-p[i][j]==1){
node nxt = DFS(nx,ny);
dp[i][j].b += nxt.a;
dp[i][j].b %= mod;
dp[i][j].c += nxt.b;
dp[i][j].c %= mod;
dp[i][j].d += (nxt.c+nxt.d);
dp[i][j].d %= mod;
}
}
return dp[i][j];
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&p[i][j]);
dp[i][j].flag = false;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(vis1(i,j)) dp[i][j].a = 0;
else dp[i][j].a = 1;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
DFS(i,j);
}
}
ll ans = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(vis2(i,j)){
ans = (ans+dp[i][j].d) % mod;
}
}
}
printf("%lld\n",ans);
return 0;
}