首页 > 其他分享 >NEFU OJ Problem1485 贪吃蛇大作战 题解

NEFU OJ Problem1485 贪吃蛇大作战 题解

时间:2023-11-19 13:34:10浏览次数:38  
标签:Problem1485 OJ int 题解 food 坐标 res dp rightarrow

  • Problem:F
  • Time Limit:1000ms
  • Memory Limit:65535K

题目

Description

贪吃蛇大家一定都玩过吧,现在宋哥也要玩这个游戏,最初的时候贪吃蛇从屏幕的左下角出发,但是有一个非常不幸的事情,就是宋哥的游戏机的左键和下键坏掉了,这意味着什么?没错!他只能操控他的蛇向右或向上走了,假设屏幕被划分为109*109的格子,而贪吃蛇从坐标为(1,1)的格子出发,每次操作可以从坐标为(x,y)的格子前往坐标为(x+1,y)或(x,y+1)的格子,在所有格子中有一些格子中有一些食物,宋哥现在想知道,他的贪吃蛇最多能吃到多少食物呢?

Input

输入的第一行包含一个数字T(1<=T<=10),代表数据组数,之后的每组数据的每一行包含一个数字n (1<=n<=1000),代表有食物的格子数量,之后的n行每一行包含三个数字xi(1<=xi<=109),yi(1&lt;=xi&lt;=109),pi(1<=xi<=10^6),分别代表格子的坐标和在这个格子里的食物数量。

Output

输出T行,第i行为第i组数据的答案。

Sample Input

2
3
1 1 1
2 2 2
3 3 3
3
1 3 1
2 2 2
3 1 3

Sample Output

6
3

Hint

Source

MGH

思路

看起来像很经典的dp问题,但是区别是点很稀疏,只有1e3的点,却有1e9*1e9的棋盘,考虑将点位置重新紧密排布, 建立一个映射将稀疏点集\(S\)映射到紧密点集\(P'\)即 \(f:\{P_i = (X_i,Y_i)\in S\}\rightarrow \{P'_i=(X'_i,Y'_i)\in S'\}\)使得\(S'\)方便使用dp。

需要保证重新排布后性质不变,分析后得知需要满足保持原本的横纵坐标的大小关系即

\[\forall P_i, P_j\in S \left\{ \begin{array}{c} x_i < x_j \rightarrow x'_i < x'_j\\ x_i = x_j \rightarrow x'_i = x'_j\\ x_i > x_j \rightarrow x'_i > x'_j\\ \end{array} \right. \]

\[\forall P_i, P_j\in S \left\{ \begin{array}{c} y_i < y_j \rightarrow y'_i < y'_j\\ y_i = y_j \rightarrow y'_i = y'_j\\ y_i > y_j \rightarrow y'_i > y'_j\\ \end{array} \right. \]

如下图所示方法,删除所有空行和空列可以实现。

image-20231119131303148 image-20231119131531135 image-20231119131346987

算法实现

  1. 对\(x\)坐标由小到大排序
  2. 对于每个点遍历从0开始分配新的\(x'\)坐标,如果某个点\(x\)坐标与上一个点相同,则分配相同的\(x'\)坐标,而不递增\(x'\)。

之后再对\(y\)坐标进行同样的操作。

完成后对\(S'\)点集进行DP即可

代码如下

#include <bits/stdc++.h>

using namespace std;

struct Food
{
    int x, y, v, _x, _y;//_x和_y代表映射后坐标
} food[1020];

int mp[1020][1020], dp[1020][1020];

bool Cmp1(Food f1, Food f2)//x排序
{
    return f1.x < f2.x;
}
bool Cmp2(Food f1, Food f2)//y排序
{
    return f1.y < f2.y;
}

int Find(int x, int y)//Dp
{
    if(dp[x][y] != -1)
        return dp[x][y];

    int res = 0;
    if(x-1 >= 0)
        res = max(res, Find(x-1,y));
    if(y-1 >= 0)
        res = max(res, Find(x,y-1));
    return dp[x][y] = res + mp[x][y];
}
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        int n;
        cin >> n;
        for (int i = 0; i < n; i ++)
            scanf("%d%d%d", &food[i].x, &food[i].y, &food[i].v);

        //x排序并分配新坐标
        sort(food, food+n, Cmp1);
        int ind_x = 1;
        food[0]._x = 1;
        for (int i = 1; i < n; i ++)
            if(food[i].x == food[i-1].x)
                food[i]._x = ind_x;
            else
                food[i]._x = ++ind_x;

        //y排序并分配新坐标
        sort(food, food+n, Cmp2);
        int ind_y = 1;
        food[0]._y = 1;
        for (int i = 1; i < n; i ++)
            if(food[i].y == food[i-1].y)
                food[i]._y = ind_y;
            else
                food[i]._y = ++ind_y;


        //普通DP过程
        for (int i = 0; i <= 1000; i ++)
            for (int j = 0; j <= 1000; j ++)
                mp[i][j] = 0;

        for (int i = 0; i < n; i ++)
            mp[food[i]._x][food[i]._y] = food[i].v;

        for (int i = 0; i <= ind_x; i ++)
            for (int j = 0; j <= ind_y; j ++)
                dp[i][j] = -1;

        dp[0][0] = 0;

        cout << Find(ind_x,ind_y) << endl;
    }
    return 0;
}

标签:Problem1485,OJ,int,题解,food,坐标,res,dp,rightarrow
From: https://www.cnblogs.com/eChorgi/p/17841939.html

相关文章

  • ICPC2023深圳部分题解(A,D,E,F,G,K,L)
    目录正题A一道好题题目大意解题思路D机器人兄弟题目大意解题思路E二合一题目大意解题思路F见面礼题目大意解题思路G相似基因序列问题题目大意解题思路K四国军棋题目大意解题思路LMary有颗有根树题目大意解题思路正题好像还没上gym所以放不了题目链接,深圳这场的题目我觉......
  • ctf.show 信息泄露部分题解
    源码泄露根据题目可以知道这个是源码泄露,所以是看源代码,查看源代码的三种方式:CTRL+U,F12,右键选择查看源代码,flag就在源代码内前台JS绕过启动靶场后给出的提示是无法查看源代码,右键和F12都无法使用,题目是前台JS绕过,所以我们进入浏览器的设置界面,搜索javascript找到后把他禁用,然后再返......
  • 洛谷 P9869 [NOIP 2023] 三值逻辑 题解
    https://www.luogu.com.cn/problem/P9869?contestId=145259看到要给变量赋初始值,还是T,F,U之类的,容易想到2-SAT。设\(1\simn+m\)的点表示\(x_1,x_2,\dots,x_{n+m}\)为T的点,其中\(x_{k+n}(1\leqk\leqm)\)表示在第\(k\)次操作被操作的变量的值(操作......
  • qemu-kvm: error: failed to set MSR x38d to x0x 【问题解决】
    问题解决创建报错在下面的issues找到解决办法https://github.com/GNS3/gns3-server/issues/1774可以尝试在VM上禁用MSR,然后检查是否可以启动qemu计算机添加内核模块参数临时修改echoY>/sys/module/kvm/parameters/ignore_msrs或者永久修改cat>/etc/modp......
  • AT_code_festival_2018_quala_b题解
    题意给定一个序列,里面的值只有可能是\(a\)或\(b\)(\(a<b\))。有\(m\)个区间,这里面的值必须是\(a\),求如何是序列总和最大。思路因为\(n\)和\(m\)都只有100,所以可以先暴力将所有值设为\(b\),再将区间里的值暴力修改为\(a\),最后统计答案。ACCODE#include<bits/stdc......
  • P9779 题解
    思路因为不一定是只有一个答案,也就是多选题。所以就转化成了在\(n\)个里面选若干个。而每种个数必须都试一次。所以答案为:\[\sum_{i=1}^{i\len}C_n^i\]\(C_n^m\)表示在\(n\)个里面选\(m\)个方案数,即组合问题。众所周知,\[2^n=\sum_{i=0}^{i\len}C_n^i\]而\(......
  • P9782 题解
    题意给定两个字符,分别是两个\(26\)进制数,\(A\)到\(Z\)分别表示\(0\)到\(25\)。求这两个字符的和。答案同样用这种\(26\)进制表示。不包含前导\(0\)。思路先转化成\(10\)进制,再转化成\(26\)进制即可。而因为只有一位所以就不用写循环,直接算出\(10\)进制下的和......
  • SP3889 Closest Number题解
    题意简述有两个\(n\)位十进制数\(a\),\(b\)。要将数字\(b\)的每一位重新排列后,使得得到的数字一个在大于等于\(a\)的情况下更接近\(a\),另一个在小于\(a\)的情况下更接近\(a\)。求这两个数,如果找不到就输出0。思路以大于等于\(a\)的为例。我们可以将\(b\)从小......
  • AT_gigacode_2019_b 题解
    本题考查基本语法。思路用while来枚举每一组数据,用if判断是否合法。在判断时需要使用逻辑运算符&&,它的意思是左右两个要求如果同时成立,则会返回true,否则返回false。\(a\gex\),\(b\gey\),\(a+b\gez\)。这三个条件都要同时成立,所以可以使用&&。ACCODE#include......
  • SP3881 题解
    前置知识最短路。思路这就是一道很简单的最短路板子,太良心了,用堆优化的Dijkstra就能过。相信大家都会这个,我就不介绍了。ACCODE#include<bits/stdc++.h>usingnamespacestd;intdis[100005],n,m,s,t,vis[100005];vector<pair<int,int>>e[100005];inlinevoiddijkst......