FatMouse and Cheese HDU - 1078 (记忆化搜索)

本文介绍了一种基于深度优先搜索的游戏算法实现,旨在解决玩家如何在一个n*n的格子中移动以获取最大得分的问题。玩家从左上角开始,在不超过规定步数的情况下向相邻格子移动,目标格子的数值必须大于当前位置的数值。

有一种游戏是的玩法是这样的:
有一个n*n的格子,每个格子有一个数字。
遵循以下规则:
1. 玩家每次可以由所在格子向上下左右四个方向进行直线移动,每次移动的距离不得超过m
2. 玩家一开始在第一行第一列,并且已经获得该格子的分值
3. 玩家获得每一次移动到的格子的分值
4. 玩家下一次移动到达的格子的分值要比当前玩家所在的格子的分值要大。
5. 游戏所有数字加起来也不大,保证所有数字的和不会超过int型整数的范围
6. 玩家仅能在n*n的格子内移动,超出格子边界属于非法操作
7. 当玩家不能再次移动时,游戏结束
现在问你,玩家所能获得的最大得分是多少?
Input有多组测试数据
每组测试样例第一行是两个整数n,m (1≤n≤100)(1≤m≤100),当n和m都是-1时为程序结束标志,直接退出即可
之后n行,每行n个数字,描述n*n的格子里的数字
Output对于每组测试数据输出一行,这一行仅有一个整数,代表玩家所能获得的最高得分 
Sample Input
3 1
1 2 5
10 11 6
12 12 7
-1 -1
Sample Output
37


解:我们可以从后往前推 先dfs找到m范围内都没有比他更大的然后他的最大得分固定再往前推

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
int dp[200][200];
int a[200][200];
int d[4][2]={-1,0,1,0,0,1,0,-1};
int n,m,ans;
int aa(int x,int y)
{
    if(1<=x&&x<=n&&1<=y&&y<=n)
        return 1;
    return 0;
}
int dd(int x,int y)
{
    int uu=0,pp;
    if(!dp[x][y])//未被找过
    {
        for(int i=1;i<=m;i++)
            for(int j=0;j<4;j++)
            {
            int xx=x+d[j][0]*i;
            int yy=y+d[j][1]*i;
             if(aa(xx,yy)&&a[xx][yy]>a[x][y])//如果在范围内有比他大的数,往下找
             {
               pp=dd(xx,yy);
               uu=max(uu,pp);
             }
            }
       dp[x][y]=uu+a[x][y];
    }
    return dp[x][y];
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if(n==-1&&m==-1) return 0;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
               scanf("%d",&a[i][j]);
     printf("%d\n",dd(1,1));
    }
}




<think>嗯,用户想了解FatMouse's Speed这个算法题的解法,可能是在准备竞赛或者学习动态规划。首先,我需要回忆下这个题目的内容。根据引用3提到的,这是一个简单的DP问题,测试数据较松,O(n&sup2;)算法也能过。题目应该是要求找出最长的子序列,满足老鼠的体重递增而速度递减。 接下来,我需要确定问题具体要求。比如输入是多个老鼠的体重和速度,要求找出最长的序列,其中每只老鼠比前只更重但更慢。同时可能需要输出这个子序列的顺序。这和最长递增子序列(LIS)问题类似,但有两个条件需要考虑。 然后,思考如何建模。通常处理这类问题的方法是先排序,将其中一个条件固定,转化为另一个条件的最长序列。例如,按体重递增排序,如果体重相同则按速度递减,这样问题转化为在速度中找最长递减子序列,但必须保证原序列中的体重严格递增。不过,可能存在相同体重的情况,这时候需要处理。例如,排序时应确保相同体重的老鼠按速度降序排列,这样在后续处理时,相同体重的不会干扰,因为后面的速度更小的话也无法满足体重递增的条件。 接下来是动态规划的思路。每个位置i的最长子序列长度可以由前面所有j<i且满足体重严格小于i且速度严格大于i的位置j的最大值加1。这样时间复杂度是O(n&sup2;),而题目中n最多是1000,所以应该是可行的。 然后考虑如何记录路径,以便最后输出选中的老鼠的顺序。这通常需要维护一个pre数组,记录每个位置的前驱节点,最后从最大长度的位置回溯。 另外,需要注意输入输出的格式。输入每行两个整数,可能有多组数据,直到文件结束。输出应该是最长子序列的长度,以及按顺序的老鼠编号(可能按原始输入的顺序,所以排序前需要记录原始位置)。 现在,验证这些思路是否正确。例如,排序是否正确处理了体重相同的情况。如果两只老鼠体重相同,即使速度不同,也不能出现在同一个序列中,因为体重必须严格递增。因此,在排序时,应该将体重相同的按速度降序排列,这样在处理时,后面的老鼠速度更小,但体重相同,不会被选中,从而避免错误。 然后,动态规划的状态转移是否正确。每个元素dp[i]表示以第i只老鼠结尾的最长子序列长度。状态转移需要遍历前面所有符合条件的元素,并取最大值加1。 路径记录的实现需要仔细处理。每个位置i的pre[i]存储前一个的位置,这样最后找到最长子序列的末尾后,可以逆序回溯得到正确的顺序。 另外,初始情况下,每个dp[i]至少是1,即自身构成一个子序列。然后逐步更新。 最后,代码的结构大致是先读取所有数据,记录原始索引,然后排序,接着进行动态规划,同时记录路径,最后找到最长子序列,并逆序输出。 可能的问题点包括:排序是否合理,如何处理体重相同的情况,动态规划条件是否正确,路径记录是否正确,以及输出时的顺序是否正确。例如,在排序后,原始索引可能需要保存,以便输出时使用原始的顺序编号。 测试用例方面,比如输入几个老鼠的数据,验证是否得到正确的最长子序列。例如,输入三只老鼠:(体重,速度)分别为(6008, 1300), (6000, 2100), (500, 2000)。排序后按体重递增,所以顺序是500,6000,6008。对应的速度是2000,2100,1300。此时最长子序列是500→6000→6008,对应的速度是2000→2100→1300,但因为速度需要递减,所以中间这个不符合,所以正确的最长子序列应该是500→6008,长度为2。或者可能需要更详细的测试。这说明在动态规划时需要严格检查体重和速度的条件。 综上,正确的解法应该是排序后应用动态规划,注意处理相同体重的情况,并且正确记录路径。</think>### FatMouse's Speed 算法题解 #### 问题描述 给定组老鼠的体重和速度数据,要求找到**最长的子序列**,满足以下条件: 1. 体重严格递增 2. 速度严格递减 3. 输出子序列长度及具体老鼠的原始输入顺序编号 #### 解题思路 1. **预处理与排序** 将老鼠按体重升序排序,若体重相同则按速度降序排序。这步固定体重顺序,将问题简化为**在速度序列中寻找最长递减子序列**2. **动态规划建模** - 定义 $dp[i]$ 表示以第 $i$ 只老鼠结尾的最长子序列长度 - 状态转移方程: $$dp[i] = \max_{\substack{j < i \\ \text{speed}[j] > \text{speed}[i]}} (dp[j] + 1)$$ - 同时记录路径 $pre[i]$ 表示前驱节点 3. **路径回溯** 通过 $pre$ 数组从最长子序列末尾回溯到起始位置,最终逆序输出原始编号。 #### 代码实现 ```python mice = [] index = 1 while True: try: w, s = map(int, input().split()) mice.append((w, s, index)) # (weight, speed, original_index) index += 1 except EOFError: break # 排序:体重升序,速度降序 mice.sort(key=lambda x: (x[0], -x[1])) n = len(mice) dp = [1] * n pre = [-1] * n max_len = 1 end_pos = 0 for i in range(n): for j in range(i): if mice[j][0] < mice[i][0] and mice[j][1] > mice[i][1] and dp[j] + 1 > dp[i]: dp[i] = dp[j] + 1 pre[i] = j if dp[i] > max_len: max_len = dp[i] end_pos = i # 路径回溯 path = [] while end_pos != -1: path.append(mice[end_pos][2]) end_pos = pre[end_pos] print(max_len) for num in reversed(path): print(num) ``` #### 关键分析 1. **时间复杂度** 动态规划部分为 $O(n^2)$,适用于 $n \leq 1000$ 的数据规模[^3] 2. **排序技巧** 通过将体重相同的元素按速度降序排列,确保后续处理时不会选择到体重相同的元素 3. **路径记录** 通过 $pre$ 数组实现路径回溯,需注意最终输出顺序要逆序 #### 典型测试用例 输入: ``` 6008 1300 6000 2100 500 2000 ``` 输出: ``` 2 3 1 ``` 说明:选择第3只(500g/2000cm/s)和第1只(6008g/1300cm/s)形成有效序列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值