HDU-4558 剑侠情缘 动态规划
题意:给定一个矩阵,矩阵上的每一点都有一个值。每次能够从任意一点开始,任意一点结束,每到一个点交替的加人的水平和剑的水平。问一共有多少种方法使得人的水平和剑的水平在最后相等。
解法:
f[x][y][k][0]表示在xy位置人的水平减去剑的水平的差值为k且该位置走奇数步的情况有多少种
f[x][y][k][1]表示在xy位置人的水平减去剑的水平的差值为k且该位置走偶数步的情况有多少种
然后维护这个数组就可以了,有一种省略了最后那个0、1的写法现在还搞不大清楚。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> char s[500][500]; int N, M; const int MOD = int(1e9)+7; int f[500][500][11][2]; // f[x][y][k][0]表示在xy位置人的水平减去剑的水平的差值为k且该位置走奇数步的情况有多少种 // f[x][y][k][1]表示在xy位置人的水平减去剑的水平的差值为k且该位置走偶数步的情况有多少种 void solve() { memset(f, 0, sizeof (f)); int ret = 0; for (int i = 1; i <= N; ++i) { for (int j = 1; j <= M; ++j) { f[i][j][s[i][j]][0] = 1; // 假设从该点出发 for (int k = 0; k < 11; ++k) { int sta1 = (k-s[i][j]+11)%11; int sta2 = (k+s[i][j])%11; if (j > 1) { // 说明能够从左边递推过来 f[i][j][k][0] += f[i][j-1][sta1][1]; f[i][j][k][0] %= MOD; f[i][j][k][1] += f[i][j-1][sta2][0]; f[i][j][k][1] %= MOD; } if (i > 1) { // 说明能够从上面递推过来 f[i][j][k][0] += f[i-1][j][sta1][1]; f[i][j][k][0] %= MOD; f[i][j][k][1] += f[i-1][j][sta2][0]; f[i][j][k][1] %= MOD; } } ret += (f[i][j][0][0] + f[i][j][0][1]) % MOD; ret %= MOD; } } printf("%d\n", ret); } int main() { int T, ca = 0; scanf("%d", &T); while (T--) { scanf("%d %d", &N, &M); for (int i = 1; i <= N; ++i) { scanf("%s", s[i]+1); for (int j = 1; j <= M; ++j) s[i][j] -= '0'; } printf("Case %d: ", ++ca); solve(); } return 0; }