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;    
}

 

posted @ 2013-05-25 09:53  沐阳  阅读(358)  评论(0编辑  收藏  举报