HDU5617 Jam's maze(dp)

题目点我点我点我


题意:从(1,1)走到(n,n),走过的路形成一个字符串,问有多少个是回文。


思路:可以想着有两个人分别从(1,1)(1,1)(n,n)(n,n)开始走,然后走到相遇,状态转移就很显然,相遇时把四个方向都扫一下即可。所以我们定义状态可以定义为f[x_1][y_1][x_2][y_2]f[x1][y1][x2][y2]表示所对应的两个点(x_1,y_1)(x_2,y_2)(x1,y1)(x2,y2),这样的话考虑到数据的范围,显然会爆Memory,然后我们想一想就是走多少步和知道x_1,x_2x1,x2的位置,就可以确定y_1,y_2y1,y2的位置,举个栗子:

(1,1)走到(3,y1),假设已知y1=3,那么步数step=3-1+y1-1=4,那现在已知步数step,倒推一下y1即可,y2同理。

于是我们把状态定义为f[i][x_1][x_2]f[i][x1][x2]即可,i表示走的步数。因为还是会爆Memory,所以我们把第一维改成滚动数组就解决问题。

难点主要是首先得想到是用dp做,因为看到回文会下意识想到后缀数组什么鬼之类的,然后就是对空间的优化。



#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define inf 0x3f3f3f3f
#define mod 5201314

int dp[2][505][505];
char Map[505][505];

void add(int &x,int y)
{
    x+=y;
    if(x>=mod)x-=mod;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",Map[i]+1);
        }
        int p=0;
        memset(dp[p],0,sizeof(dp[p]));
        dp[p][1][n]=Map[1][1]==Map[n][n];
        for(int i=1;i<n;i++)
        {
            memset(dp[!p],0,sizeof(dp[!p]));
            for(int x1=1;x1<=i+1;x1++)
            {
                for(int x2=n;x2>=n-i;x2--)
                {
                    int y1=i+2-x1;
                    int y2=2*n-i-x2;
                    if(Map[x1][y1]!=Map[x2][y2])continue;
                    add(dp[!p][x1][x2],dp[p][x1][x2]);
                    add(dp[!p][x1][x2],dp[p][x1][x2+1]);
                    add(dp[!p][x1][x2],dp[p][x1-1][x2+1]);
                    add(dp[!p][x1][x2],dp[p][x1-1][x2]);
                }
            }
            p^=1;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            add(ans,dp[p][i][i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}



你可能感兴趣的:(HDU5617 Jam's maze(dp))