HDU 5617 Jam's maze(dp)

Description
Jam走进了一个迷宫,他要想走出这个迷宫,必须找到一条路径,使得这条路径是回文的,当然他可不屑于去走出这个迷宫,聪明的他一定要找出有多少种方案走出这个迷宫。在一个N*N大小的迷宫,这个迷宫全由大写字母组成,他会从左上角走到右下角,然后把所有经过的字符连成一个串,当然只能往下和往右走,问有多少种方案可以走出来,当然答案会很大,所以答案和5201314取模输出
Input
第一行T(1≤T≤10),表示T组数据。
接下来T组数据:
每组数据第一行为N(1≤N≤500)表示矩阵的行和列
接下来N行N列N*N个字符
Output
输出合法方案数
Sample Input
1
4
ABCD
BEFE
CDEB
GCBA
Sample Output
12
Solution
一个人从(1,1)走了一个回文串到(n,n)其实就是两个人分别从(1,1)和(n,n)出发走了相同的字符串最后相遇,用dp[step][x1][y1][x2][y2]表示走了step步,第一个人走到(x1,y1)点,第二个人走到了(x2,y2)点,且两人走过的字符串完全相同的方案数,那么有
dp[step][x1][y1][x2][y2]+=dp[step-1][x1-1][y1][x2+1][y2]
dp[step][x1][y1][x2][y2]+=dp[step-1][x1][y1-1][x2+1][y2]
dp[step][x1][y1][x2][y2]+=dp[step-1][x1][y1-1][x2][y2+1]
dp[step][x1][y1][x2][y2]+=dp[step-1][x1-1][y1][x2][y2+1]
考虑到空间太大所以要优化一下,首先第一维可以滚动一下,然后发现step确定时,y1和y2可以由x1和x2确定,故只需要开三维即可
Code

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
#define mod 5201314
#define maxn 555
int T,n,dp[2][maxn][maxn];
char m[maxn][maxn];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%s",m[i]+1);
        memset(dp,0,sizeof(dp));
        int cur=0;
        dp[0][1][n]=(m[1][1]==m[n][n]);
        for(int i=1;i<n;i++)
        {
            memset(dp[cur^1],0,sizeof(dp[cur^1]));
            for(int x1=1;x1<=i+1;x1++)
                for(int x2=n;x2>=n-i;x2--)
                {
                    int y1=i+2-x1,y2=2*n-i-x2;
                    if(m[x1][y1]!=m[x2][y2])continue;
                    dp[cur^1][x1][x2]=(dp[cur^1][x1][x2]+dp[cur][x1][x2])%mod;
                    dp[cur^1][x1][x2]=(dp[cur^1][x1][x2]+dp[cur][x1][x2+1])%mod;
                    dp[cur^1][x1][x2]=(dp[cur^1][x1][x2]+dp[cur][x1-1][x2])%mod;
                    dp[cur^1][x1][x2]=(dp[cur^1][x1][x2]+dp[cur][x1-1][x2+1])%mod;
                }
            cur^=1;
        }
        int ans=0;
        for(int i=1;i<=n;i++)ans=(ans+dp[cur][i][i])%mod;
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值