http://hihocoder.com/problemset/problem/1290
这题是这次微软笔试的第三题,过的人比第一题少一点,这题一眼看过去就是动态规划,不过转移方程貌似不是很简单,调试了比较久才正确,不过好在是1A,但是最后只留了一个小时多一点给B题,也导致了B题最后也没能AC掉。首先状态是很好确定的p[i][j][k]表示走到第i行第j个格子时,方向是k的情况下的最小改变格子数目。(k from {0, 1})而且由于只有往下和往右走,所以中间过程进行转移时改变的格子不会影响后续过程中的转移,所以只需要分析p[i][j][0]和p[i][j][1]分别怎么由上面和左边的格子得到。情况比较多,基本上在代码里就可以看明白,不过需要对几处边界条件判断一下,比如第一列无法由左边格子得到,第一行无法由上面的格子得到,还有就是向下和向右撞到边界的时候。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <set> #include <map> #include <queue> #include <vector> #include <string> #define LL long long using namespace std; int n, m; char str[105][105]; int p[105][105][2]; void input() { for (int i = 0; i < n; ++i) scanf("%s", str[i]); memset(p, -1, sizeof(p)); } void work() { int t; if (str[0][0] == ‘.‘) p[0][0][0] = 0; else p[0][0][0] = 1; if (m == 1 || str[0][1] == ‘b‘) p[0][0][1] = 0; else p[0][0][1] = 1; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (i == 0 && j == 0) continue; if (j == 0) { //left if (i+1 == n || str[i+1][j] == ‘b‘) p[i][j][0] = p[i-1][j][1]; else p[i][j][0] = p[i-1][j][1]+1; if (str[i][j] == ‘b‘) p[i][j][0]++; //bottom p[i][j][1] = p[i-1][j][1]; if (str[i][j] == ‘b‘) p[i][j][1]++; } else { //left p[i][j][0] = p[i][j-1][0]; if (str[i][j] == ‘b‘) p[i][j][0]++; if (i > 0) { t = p[i-1][j][1]; if (str[i][j] == ‘b‘) t++; if (i+1 == n || str[i+1][j] == ‘b‘) p[i][j][0] = min(p[i][j][0], t); else p[i][j][0] = min(p[i][j][0], t+1); } //bottom p[i][j][1] = p[i][j-1][0]; if (str[i][j] == ‘b‘) p[i][j][1]++; if (!(j+1 == m || str[i][j+1] == ‘b‘)) p[i][j][1]++; if (i > 0) { t= p[i-1][j][1]; if (str[i][j] == ‘b‘) t++; p[i][j][1] = min(p[i][j][1], t); } } } } printf("%d\n", min(p[n-1][m-1][0], p[n-1][m-1][1])); } int main() { //freopen("test.in", "r", stdin); while (scanf("%d%d", &n, &m) != EOF) { input(); work(); } return 0; }
时间: 2024-10-12 20:40:16