[思维][dp]Zero Path CF1695C

59 篇文章 0 订阅
26 篇文章 0 订阅

You are given a grid with nn rows and mm columns. We denote the square on the i-th (1≤i≤n) row and j-th (1≤j≤m) column by (i,j) and the number there by aij. All numbers are equal to 1 or to −1.

You start from the square (1,1) and can move one square down or one square to the right at a time. In the end, you want to end up at the square (n,m).

Is it possible to move in such a way so that the sum of the values written in all the visited cells (including a11 and anm) is 0?

 

Input

Each test contains multiple test cases. The first line contains the number of test cases t (1≤t≤10^4). Description of the test cases follows.

The first line of each test case contains two integers n and m (1≤n,m≤1000)  — the size of the grid.

Each of the following n lines contains mm integers. The j-th integer on the i-th line is aij (aij=1 or −1)  — the element in the cell (i,j).

It is guaranteed that the sum of n⋅m over all test cases does not exceed 10^6.

Output

For each test case, print "YES" if there exists a path from the top left to the bottom right that adds up to 0, and "NO" otherwise. You can output each letter in any case.

Example

input

5
1 1
1
1 2
1 -1
1 4
1 -1 1 -1
3 4
1 -1 -1 -1
-1 1 1 -1
1 1 1 -1
3 4
1 -1 1 1
-1 1 -1 1
1 -1 1 1

output

NO
YES
YES
YES
NO

Note

One possible path for the fourth test case is given in the picture in the statement.

题意: 有一个由-1和1组成的矩阵,询问是否存在一条从(1, 1)到(n, m)的路径,移动时只能向右或向下走,其路径和为0。

分析: 利用dp可以求出从(1, 1)到(n, m)的最大值max和最小值min,如果min <= 0 <= max,则一定存在一条路径能从(1, 1)走到(n, m)且路径和为0。

下面给出证明:存在如下一条路径,沿着上边界和右边界到达(n, m),

此时可以将右上角的点变换至其左下方以得到一条新路径,

此时路径和从原来的路径和基础上增加了2 ,之后以同样方式可以得到更多的新路径,最终以此方式可以遍历得到全部的路径,在过程中显然会遍历得到最小值路径min和最大值路径max,也就是说一定存在一个路径和从min值增加到max值的过程,而这个过程中路径值每次都会增减2,所以一定会经过值为0的状态,也就得到了路径值为0的一条路径。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#define inf 0x3f3f3f3f
using namespace std;

int a[1005][1005], mi[1005][1005], ma[1005][1005];

signed main()
{
	int T;
	cin >> 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]);
		ma[1][1] = mi[1][1] = a[1][1];
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= m; j++){
				if(i == 1 && j == 1) continue;
				mi[i][j] = min(i-1>=1?mi[i-1][j]:inf, j-1>=1?mi[i][j-1]:inf)+a[i][j];
				ma[i][j] = max(i-1>=1?ma[i-1][j]:-inf, j-1>=1?ma[i][j-1]:-inf)+a[i][j];
			}
		if((n+m-1)&1) puts("NO");
		else if(mi[n][m] <= 0 && ma[n][m] >= 0) puts("YES");
		else puts("NO");
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值