原题链接(链接)
题目大意:在N*M的网格上,从(1,1)开始向四个方向移动,每个方向只能移动一次,求到达(N,M)最小步数。
题解:这些移动是对称的,因此我们可以假设n≥mn≥m.如果没有解决方案,如果m=1m=1和n≥3n≥3,因为一个人只能上下移动,但需要连续两次向下移动才能达到(n,1)(n,1).否则,就有解决方案。
一个人至少应该向下移动n−1n−1时间,并且禁止连续两次这样做,所以另一个n−2n−2移动是必要的(11在每对之间)。所以至少n−1+n−2=2⋅n−3n−1+n−2=2⋅n−3需要移动。如果n+mn+m是偶数,然后又是一个,因为奇偶校验a+ba+b每次移动后都会发生变化,并且奇偶校验甚至在第一次移动之前和最后一次移动之后,因此移动总数应该是偶数。
该下限有一个构造:交替向下和向右移动。到达后mm-第 0 列,重复以下移动顺序:向下、向左、向下、向右。有了这个44移动长序列,可以向下移动两次。
因此,我们将达到(n−1,米)(n−1,m),那么需要再移动一次,否则我们将到达(n,m)(n,m).如果我们添加所有这些移动,我们得到公式:如果n+mn+m即使这样:2⋅(m−1)+4⋅(n−m)/2=2⋅n−22⋅(m−1)+4⋅(n−m)/2=2⋅n−2,如果n+mn+m很奇怪, 那么:2⋅(m−1)+4⋅(n−m−1)/2+1=2⋅n−32⋅(m−1)+4⋅(n−m−1)/2+1=2⋅n−3.
图解:以N=10,M=5为例
代码实现:
#include <iostream>
using namespace std;
int T, n, m;
int main()
{
ios_base::sync_with_stdio(false);
cin >> T;
while (T--) {
cin >> n >> m;
if (n < m) {
swap(n, m);
}
if (m == 1 && n >= 3) {
cout << -1 << "\n";
}
else {
cout << 2 * n - 2 - (n + m) % 2 << "\n";
}
}
return 0;
}