题目:C. Zero Path
考点:DP
题意:在一个 n × m n \times m n×m 的矩阵中,找出一条从 ( 1 , 1 ) (1,1) (1,1) 到 ( n , m ) (n,m) (n,m) 总和为 0 0 0 的路径,其中每次移动只能向下或向右,如果存在总和为 0 0 0 的路径,输出 Y E S YES YES ,否则输出 N O NO NO 。
官方题解:如果 n + m n+m n+m 为偶数,那么从左上角到右下角的如何路径都将为奇数,因此一定是非零的。这种情况是不存在和为零的路径。
对于网格中的每个位置 ( i , j ) (i,j) (i,j),我们定义 m a x i , j max_{i,j} maxi,j 为从左上角开始到 ( i , j ) (i,j) (i,j) 结束的路径的最大可能和。同样, m i n i , j min_{i,j} mini,j 被定义为从左上角开始到 ( i , j ) (i,j) (i,j) 结束的最小可能和。这些值可以用 D P DP DP 来计算,其中
m a x i , j = a i , j + m a x ( m a x ( i − 1 ) , j , m a x i , ( j − 1 ) ) m i n i , j = a i , j + m i n ( m i n ( i − 1 ) , j , m i n i , ( j − 1 ) ) max_{i,j}=a_{i,j}+max(max_{(i-1),j},max_{i,(j-1)})\\ min_{i,j}=a_{i,j}+min(min_{(i-1),j}, min_{i,(j-1)}) maxi,j=ai,j+max(max(i−1),j,maxi,(j−1))mini,j=ai,j+min(min(i−1),j,mini,(j−1))
如果 0 < m i n n , m 0<min_{n,m} 0<minn,m 或 m a x n , m < 0 max_{n,m}<0 maxn,m<0 ,则没有路径加起来为 0 0 0。否则, 0 0 0 位于 [ m i n n , m , m a x n , m ] [min_{n,m},max_{n,m}] [minn,m,maxn,m] 范围内,我们可以证明有一个有效的解决路径。证明。设 p 1 p_1 p1 是一条从 ( 1 , 1 ) (1,1) (1,1) 到 ( n , m ) (n,m) (n,m) 的路径,加起来为 m i n n , m min_{n,m} minn,m, p 2 p_2 p2 是另一条这样的路径,加起来为 m a x n , m max_{n,m} maxn,m。这些路径中的每一条都由 n − 1 n-1 n−1 个下移和 m − 1 m-1 m−1 个右移组成,所以它可以表示为长度为 n + m − 2 n+m-2 n+m−2 的 " R R R "和 " D D D "的字符串。我们可以通过一连串的操作将 p 1 p_1 p1 移动到 p 2 p_2 p2,其中交换两个相邻(且不同)的字符。从视觉上看,我们所做的是将路径上的一个方块替换成斜向相邻的一个方块。下图显示了路径上的一个可能的操作。
请注意,在每一步中,路径上的数值之和都会发生变化,是 − 2 , 0 , 2 -2,0,2 −2,0,2 。因此,在进行了这一连串的操作后,从 p 1 p_1 p1 到 p 2 p_2 p2,我们已经将总和为 m i n n , m min_{n,m} minn,m 的路径移到了总和为 m a x n , m max_{n,m} maxn,m 的路径上,每一步的总和都改变了 − 2 , 0 , 2 -2,0,2 −2,0,2 。因此,由于 m i n n , m min_{n,m} minn,m 和 m a x n , m max_{n,m} maxn,m 都是偶数,而且 m i n n , m ≤ 0 ≤ m a x n , m min_{n,m}≤0≤max_{n,m} minn,m≤0≤maxn,m,在这一操作序列的某个点上,路径的和一定是零。
#include<stdio.h>
#include<algorithm>
using namespace std;
const int N = 1e3 + 10,INF = 0x3f3f3f3f;
int a[N][N];
int maxv[N][N],minv[N][N];
int main(){
int t;
scanf("%d",&t);
while(t --) {
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
scanf("%d",&a[i][j]);
maxv[i][j] = -INF;
minv[i][j] = INF;
}
}
maxv[1][1] = minv[1][1] = a[1][1];
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(i != 1) maxv[i][j] = max(maxv[i][j],a[i][j]+maxv[i-1][j]);
if(j != 1) maxv[i][j] = max(maxv[i][j],a[i][j]+maxv[i][j-1]);
if(i != 1) minv[i][j] = min(minv[i][j],a[i][j]+minv[i-1][j]);
if(j != 1) minv[i][j] = min(minv[i][j],a[i][j]+minv[i][j-1]);
}
}
if((n - 1 + m) % 2 == 1) printf("NO\n");
else {
if(maxv[n][m] >=0 && minv[n][m] <=0) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
/*
1
3 4
-1 -1 1 1
-1 -1 -1 -1
-1 -1 -1 -1
*/