2019 ICPC Asia Nanjing Regional C. Digital Path

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:

  • adjacent boxes in the walk share a common edge;
  • the walk is maximal, which cannot be extended;
  • the walk contains at least four boxes;
  • going from one end to the other, the increment of values for any two adjacent boxes is exactly one.

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];
  • flag:就是記錄是否DFS過,記憶化。
  • a:該點能否可以向外延伸一個點,可以的話就是 0,不可以是 1
  • b:該點是否可以向外延伸兩個點,假設該點是 now,與它相鄰的點是 nxti,那麼很明顯 now.b = ∑ nxti.a。
  • c:該點是否可以向外延伸三個點,假設該點是 now,與它相鄰的點是 nxt1,那麼很明顯 now.c = ∑ nxti.b。
  • d:該點是否可以向外延伸四個及以上的點,假設該點是 now,與它相鄰的點是 nxt1,那麼很明顯 now.d = ∑ (nxti.c+nxt.d)。

然後三個判斷函數:

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<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章