HDU 5617:Jam's maze 又被DP教育了

Jam's maze

 
 Accepts: 59
 
 Submissions: 215
 Time Limit: 3000/1500 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
Jam走进了一个迷宫,他要想走出这个迷宫,必须找到一条路径,使得这条路径是回文的
当然他可不屑于去走出这个迷宫,聪明的他一定要找出有多少种方案走出这个迷宫
在一个N*NNN大小的迷宫,这个迷宫全由大写字母组成
他会从左上角走到右下角,然后把所有经过的字符连成一个串,当然只能往下和往右走,问有多少种方案可以走出来
当然答案会很大,所以答案和52013145201314取模输出
输入描述
第一行T(1 \leq T \leq 10)T(1T10),表示TT组数据。
接下来TT组数据:
每组数据第一行为N(1 \leq N \leq 500)N(1N500)表示矩阵的行和列
接下来NNNNN*NNN个字符
输出描述
 
 
输入样例
1
4
ABCD
BEFE
CDEB
GCBA
输入样例
12
输出样例
有1种走法是"ABCDCBA"
有1种走法是"ABCGCBA"
有4种走法是"ABEDEBA"
有6种走法是"ABEFEBA"
所以共有12=6+4+1=1种走法可行

补一下题。。。

表示这道题真的是又被教育了。。。

一开始WA的代码是这样

#pragma comment(linker, "/STACK:102400000,102400000")
#pragma warning(disable:4996)  
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;

#define INF 0x3fffffff
typedef long long ll;

const int mod = 1e9 + 7;
const int maxn = 505;

int n;
char val[maxn][maxn];
int dp[2][maxn][maxn];

void add(int &x, int y)
{
    x = (x + y) % mod;
}

void input()
{
    int i;
    scanf("%d", &n);

    for (i = 1; i <= n; i++)
    {
        scanf("%s", val[i] + 1);
    }
}

void solve()
{
    int i, j, k, x1, x2, y1, y2;
    dp[0][1][1] = (val[1][1] == val[n][n]);

    k = 1;
    for (i = 2; i <= n - 1; i++)
    {
        memset(dp[k], 0, sizeof(dp[k]));
        for (x1 = 1; x1 <= i; x1++)
        {
            for (x2 = n; x2 >= n - i + 1; x2--)
            {
                y1 = i - x1 + 1;
                y2 = 2 * n - x2 - i + 1;

                 if (val[x1][y1] != val[x2][y2])continue;
                add(dp[k][x1][y1], dp[!k][x1 - 1][y1]);
                add(dp[k][x1][y1], dp[!k][x1][y1 - 1]);
            }
        }
        k = !k;
    }
    int ans = 0;
    for (i = 1; i <= n; i++)
    {
        add(ans, dp[!k][i][n - i]);
    }
    printf("%d\n", ans);
}

int main()
{
    //freopen("i.txt","r",stdin);
    //freopen("o.txt","w",stdout);

    int t;
    scanf("%d", &t);
    
    while (t--)
    {
        input();
        solve();
    }

    //system("pause");
    return 0;
}

我用dp[2][x1][y1]记录相等的情况,后来调试的时候发现这样不行 如果x1>x2||y1>y2这种情况也有记录了。所以只记录一边的是绝对绝对不行的。

用dp[2][x1][x2]水过。。。真的是欠考虑,又被教育了。

总结一下这里:

 add(dp[k][x1][x2], dp[!k][x1][x2]);
 add(dp[k][x1][x2], dp[!k][x1 - 1][x2]);
 add(dp[k][x1][x2], dp[!k][x1][x2 + 1]);
 add(dp[k][x1][x2], dp[!k][x1 - 1][x2 + 1]);

因为这道题在已知步数的情况下,知道x可以求出y。那么在判定val[x1][y1]==val[x2][y2]相等之后,可能的方向有四种,(x1-1,y1) (x1,y1-1) (x2+1,y2) (x2,y2+1)。因为外面是步数的循环所以直接用x1 x2可以直接表示方向了。

代码:

#pragma warning(disable:4996)  
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;

#define INF 0x3fffffff
typedef long long ll;

const int mod = 5201314;
const int maxn = 505;

int n;
char val[maxn][maxn];
int dp[2][maxn][maxn];

void add(int &x, int y)
{
    x = (x + y) % mod;
}

void input()
{
    int i;
    scanf("%d", &n);

    for (i = 1; i <= n; i++)
    {
        scanf("%s", val[i] + 1);
    }
}

void solve()
{
    int i, j, k, x1, x2, y1, y2;
    dp[0][1][n] = (val[1][1] == val[n][n]);

    k = 1;
    for (i = 2; i <= n; i++)
    {
        memset(dp[k], 0, sizeof(dp[k]));
        for (x1 = 1; x1 <= i; x1++)
        {
            for (x2 = n; x2 >= n - i + 1; x2--)
            {
                y1 = i - x1 + 1;
                y2 = 2 * n - x2 - i + 1;

                 if (val[x1][y1] != val[x2][y2])continue;
                
                add(dp[k][x1][x2], dp[!k][x1][x2]);
                add(dp[k][x1][x2], dp[!k][x1 - 1][x2]);
                add(dp[k][x1][x2], dp[!k][x1][x2 + 1]);
                add(dp[k][x1][x2], dp[!k][x1 - 1][x2 + 1]);
            }
        }
        k = !k;
    }
    int ans = 0;
    for (i = 1; i <= n; i++)
    {
        add(ans, dp[!k][i][i]);
    }
    printf("%d\n", ans);
}

int main()
{
    //freopen("i.txt","r",stdin);
    //freopen("o.txt","w",stdout);

    int t;
    scanf("%d", &t);
    
    while (t--)
    {
        input();
        solve();
    }

    //system("pause");
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值