题意:在一个 n * m 的矩阵中, ' . ' 代表可以通行, ' # ' 代表障碍,每次只能向右或者向下走, 让你选择最少的点将它们变成障碍, 使不存在(1, 1)到 (n,m)的通路, (1,1)和(n,m)不能是障碍;
题解:由“显然定理”可知, 答案只有三种情况(0、1、2), 最多我只需要将(n-1,m),(n,m-1) 变成障碍,那么就不存在(1, 1)到 (n,m)的通路。
- 答案为 0 , 那么说明不存在(1, 1)到 (n,m)的通路, 很多方法可以判断。
- 现在只需要判断出答案为 1 或者答案为 2 的情况。 答案为 1 ,显然,从(1, 1)到 (n,m)的所有通路,都经过 某一个点。
- 现在问题转化为了求经过任意一点的(1, 1)到 (n,m)通路的个数。
- dp[i][j] 表示从(1,1)到(i,j)的方案数,d[i][j] 表示从(n,m)到(i,j)的方案数, 任意一点的(1, 1)到 (n,m)通路的个数 = dp[i][j] * d[i][j]; if dp[i][j] * d[i][j] = dp[0][0] * d[0][0], 答案为 1;
- 由于 矩阵比较大, 所以 dp 肯定会爆 ll , 需要hash一下
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+10;
int n, m;
int mod[2] = {100000007, 1000000007};
char *s[N];
int *g[N];
ll *d[2][N], *dp[2][N];
void init(){
for(int i = 0; i <= n+1; i++)
for(int j = 0; j <= m+1; j++)
for(int k = 0; k < 2; k++)
d[k][i][j] = dp[k][i][j] = 0;
}
int main(){
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i = 0; i <= n+1; i++){
s[i] = new char[m+10];
for(int j = 0; j < 2; j++){
d[j][i] = new long long [m+10];
dp[j][i] = new long long [m+10];
}
}
init();
for(int i = 1; i <= n; i++){
cin >> s[i]+1;
}
d[0][n][m+1] = 1;
d[1][n][m+1] = 1;
dp[0][0][1] = 1;
dp[1][0][1] = 1;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(s[i][j] == '#') continue;
dp[0][i][j] = (dp[0][i-1][j] + dp[0][i][j-1]) % mod[0];
dp[1][i][j] = (dp[1][i-1][j] + dp[1][i][j-1]) % mod[1];
}
}
for(int i = n; i >= 1; i--){
for(int j = m; j >= 1; j--){
if(s[i][j] == '#') continue;
d[0][i][j] = (d[0][i+1][j] + d[0][i][j+1]) % mod[0];
d[1][i][j] = (d[1][i+1][j] + d[1][i][j+1]) % mod[1];
}
}
if(dp[0][n][m] == 0 && dp[1][n][m] == 0){
cout << "0\n";
return 0;
}
ll tmp1 = dp[0][1][1] * d[0][1][1] % mod[0];
ll tmp2 = dp[1][1][1] * d[1][1][1] % mod[1];
bool flag = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(i == 1 && j == 1) continue;
if(i == n && j == m) continue;
if(dp[0][i][j]*d[0][i][j]%mod[0]==tmp1 && dp[1][i][j]*d[1][i][j]%mod[1]==tmp2 ){
flag = 1;
break;
}
}
if(flag) break;
}
if(flag)
cout << "1\n";
else cout << "2\n";
return 0;
}