状态压缩的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 处要注意,新加入一条路径时,要把能量差取反,使整个状态转移保持一致