2013金山西山居创意游戏程序挑战赛——复赛(1) 剑侠情缘

状态压缩的dp问题

先看一段超时的代码。。。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <cmath>
using namespace std;
char tpcha[500];
int data[500][500];
int dp[2][500][11][11][2];
const int MOD = 1000000007;
int main()   
{   
#ifndef ONLINE_JUDGE 
    freopen("in.txt", "r", stdin);
#endif
    int t, cs, i, j, a, b;
    int n, m;
    int tp;
    cin>>t;
    cs = 0;
    while (t--)
    {
        
        memset(dp, 0, sizeof dp);
        printf("Case %d: ", ++cs);
        cin>>n>>m;
        for ( i = 1; i<= n; i++)
        {
            cin>>tpcha;
            for (j = 0; j< m; j++)
            {
                data[i][j+1] = tpcha[j]-'0';
            }
        }
        
        int now, bef;
        int cao = 0;
        for (i = 1; i<= n; i++)
        {
            now = i%2;
            bef = (i+1)%2;
            
            for (j = 1; j<= m; j++)
            {
                for (a = 0; a<= 10; a++)
                {
                    for (b = 0; b<= 10; b++)
                    {
                        dp[now][j][a][b][1] = dp[now][j][a][b][0] = 0;
                        tp = data[i][j];
                        if (b >= tp)
                            dp[now][j][a][b][1] += dp[bef][j][a][b-tp][0],dp[now][j][a][b][1] += dp[now][j-1][a][b-tp][0];
                        else
                            dp[now][j][a][b][1] += dp[bef][j][a][11+b-tp][0], dp[now][j][a][b][1] += dp[now][j-1][a][11+b-tp][0];
                        
                        if (a >= tp)
                            dp[now][j][a][b][0] += dp[bef][j][a-tp][b][1], dp[now][j][a][b][0] += dp[now][j-1][a-tp][b][1];
                        else
                            dp[now][j][a][b][0] += dp[bef][j][11+a-tp][b][1], dp[now][j][a][b][0] += dp[now][j-1][11+a-tp][b][1];
                        
                        if (dp[now][j][a][b][0] > MOD)
                            dp[now][j][a][b][0] %= MOD;
                        if (dp[now][j][a][b][1] > MOD)
                            dp[now][j][a][b][1] %= MOD;
                    }
                }
                if (i > 1)
                    dp[now][j][data[i-1][j]][data[i][j]][1]++;
                if (j > 1)
                    dp[now][j][data[i][j-1]][data[i][j]][1]++;
                
                for (a = 0; a<= 10; a++)
                {
                    cao += dp[now][j][a][a][0]+dp[now][j][a][a][1];
                    if (cao > MOD)        
                        cao %= MOD;
                }
            }
        }
        printf("%d\n", cao);
    }
    return 0;
}
在这里用了最直观的的 dp[2][500][11][11][2],dp[滚动数组(行)][列][人的能量][剑的能量][当前加能量的对象 0人 1剑]

时间为 n*m*11*11,果断超了

后来想到所限制的能量范围0-10是一个循环,在这个循环中可以把人和剑的能量关系压缩为两者的差值

那么状态转移时,将上一差值取反加上当前的能量就是新的差值

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <cmath>
using namespace std;
const int MAXN = 500;
const int MOD = 1e9+7;
int dp[MAXN][MAXN][11];
char tpchar[MAXN];
int valu[MAXN][MAXN];
inline mabs(int a)
{
    return a>0?a:-a;
}
int main()   
{   
#ifndef ONLINE_JUDGE 
    freopen("in.txt", "r", stdin);
#endif
    int i, j;
    int t, cs = 0;
    int n, m;
    cin>>t;
    while (t--)
    {
        printf("Case %d: ", ++cs);
        cin>>n>>m;
        for (i = 0; i< n; i++)
        {
            cin>>tpchar;
            for ( j = 0; j< m; j++)
                valu[i][j] = tpchar[j]-'0';
        }
        memset(dp, 0, sizeof dp);
        int cnt = 0;
        int a, b, c, d;
        for (i = 0; i< n; i++)
        {
            for (j = 0; j< m; j++)
            {
                for ( int k = 0; k< 11; k++)
                {
                    a = (11-k)%11;
                    b = (a+valu[i+1][j])%11;
                    dp[i+1][j][b] += dp[i][j][k];
                    dp[i+1][j][b]%=MOD;
                    b = (a+valu[i][j+1])%11;
                    dp[i][j+1][b] += dp[i][j][k];
                    dp[i][j+1][b]%=MOD;

                }
                a = valu[i][j]-valu[i+1][j];// 1
                dp[i+1][j][(11-a)%11]++;
                a = valu[i][j]-valu[i][j+1];// 2
                dp[i][j+1][(11-a)%11]++;
                cnt += dp[i][j][0];
                cnt %= MOD;
            }
        }
        cout<<cnt<<endl;
    }
    return 0;
}
其中1 和 2 处要注意,新加入一条路径时,要把能量差取反,使整个状态转移保持一致



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值