HDU_5617Jam's maze

这道题一开始看起来确实有点蒙,首先想到的就是DP,这个矩阵太明显了,但是不是很清楚状态转移方程应该怎么搞,而且数据量有点大。
其实可以这么理解,让(1,1)和(n,n)同时向中间走,在中间汇合,定义f[x1][y1][y1][y2]为从初始点到(x1,y1)(x2,y2)两点时,构成的子串相同的方案数,例如在题目样例中,f[1][2][3][4]就应该等于1,因为同时构成”AB”这个子串,好的那么状态转移方程呼之欲出f[x1][y1][x1][y1]=f[x1][y1-1][x2][y2+1]+f[x1][y1-1][x2+1][y2]+f[x1-1][y1][x2][y2+1]+f[x1-1][y1][x2+1][y2]。
但是很明显,这样就会爆内存,所以要优化,新定义一个变量i表示已经走得步数,那么y1=i-x1+2,y2=2*n-(x2+i)。好的,那么现在的状态转移方程就变成了这样f[i][x1][x2]。
对了,为了节省空间,步数那一维用了滚动数组。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
#include <map>
#include <cmath>
#include <vector>
using namespace std;
#define N 500010
#define pi acos(-1.0)
#define mod 5201314
#define inf 0x3f3f3f3f
#define pb(x) push_back((x))
typedef long long ll;
typedef unsigned long long ull;
char a[510][510];
int dp[2][510][510];
int main(){
    int n,t,y1,y2;
    scanf("%d",&t);
    while(t--){
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",&a[i]);
        }
        int p=0;
        dp[0][1][n]=(a[1][0]==a[n][n-1]);
        for(int i=1;i<n;i++){
            for(int k=1;k<=n;k++)
              for(int j=1;j<=n;j++) 
                dp[!p][j][k]=0;
            for(int x1=1;x1<=i+1;x1++){
                for(int x2=n;x2>=n-i;x2--){
                    y1=i-x1+2;
                    y2=2*n-(x2+i);
                    if(a[x1][y1-1]!=a[x2][y2-1]) continue;
                    dp[!p][x1][x2]=(dp[!p][x1][x2]+dp[p][x1][x2])%mod;
                    dp[!p][x1][x2]=(dp[!p][x1][x2]+dp[p][x1][x2+1])%mod;
                    dp[!p][x1][x2]=(dp[!p][x1][x2]+dp[p][x1-1][x2])%mod;
                    dp[!p][x1][x2]=(dp[!p][x1][x2]+dp[p][x1-1][x2+1])%mod;
                }
            }
            p=!p;
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            ans+=dp[p][i][i];
        }
        printf("%d\n",ans%mod);
    }
    return 0;
}

你可能感兴趣的:(dp,动态规划,BestCoder)