(中等) POJ 1054 The Troublesome Frog,记忆化搜索。

Description

In Korea, the naughtiness of the cheonggaeguri, a small frog, is legendary. This is a well-deserved reputation, because the frogs jump through your rice paddy at night, flattening rice plants. In the morning, after noting which plants have been flattened, you want to identify the path of the frog which did the most damage. A frog always jumps through the paddy in a straight line, with every hop the same length: 
 
Your rice paddy has plants arranged on the intersection points of a grid as shown in Figure-1, and the troublesome frogs hop completely through your paddy, starting outside the paddy on one side and ending outside the paddy on the other side as shown in Figure-2: 
 
Many frogs can jump through the paddy, hopping from rice plant to rice plant. Every hop lands on a plant and flattens it, as in Figure-3. Note that some plants may be landed on by more than one frog during the night. Of course, you can not see the lines showing the paths of the frogs or any of their hops outside of your paddy ?for the situation in Figure-3, what you can see is shown in Figure-4: 
 
From Figure-4, you can reconstruct all the possible paths which the frogs may have followed across your paddy. You are only interested in frogs which have landed on at least 3 of your rice plants in their voyage through the paddy. Such a path is said to be a frog path. In this case, that means that the three paths shown in Figure-3 are frog paths (there are also other possible frog paths). The vertical path down column 1 might have been a frog path with hop length 4 except there are only 2 plants flattened so we are not interested; and the diagonal path including the plants on row 2 col. 3, row 3 col. 4, and row 6 col. 7 has three flat plants but there is no regular hop length which could have spaced the hops in this way while still landing on at least 3 plants, and hence it is not a frog path. Note also that along the line a frog path follows there may be additional flattened plants which do not need to be landed on by that path (see the plant at (2, 6) on the horizontal path across row 2 in Figure-4), and in fact some flattened plants may not be explained by any frog path at all.

Your task is to write a program to determine the maximum number of landings in any single frog path (where the maximum is taken over all possible frog paths). In Figure-4 the answer is 7, obtained from the frog path across row 6.

  十分蛋疼的题意描述,就是给一个图,上面有很多点,然后问最长的一个轨迹是多少。

  刚开始想错了方向,一直在想从整体的角度怎么DP,后来百度发现是搜索,然后才想到了直接枚举两个点,然后dfs就好,其中加上记忆化,就可以了。

  注意卡内存,所以说要hash存点,hash值也要取个合适的,第一次就TLE了。。。

代码如下:

// ━━━━━━神兽出没━━━━━━
//      ┏┓       ┏┓
//     ┏┛┻━━━━━━━┛┻┓
//     ┃           ┃
//     ┃     ━     ┃
//     ████━████   ┃
//     ┃           ┃
//     ┃    ┻      ┃
//     ┃           ┃
//     ┗━┓       ┏━┛
//       ┃       ┃
//       ┃       ┃
//       ┃       ┗━━━┓
//       ┃           ┣┓
//       ┃           ┏┛
//       ┗┓┓┏━━━━━┳┓┏┛
//        ┃┫┫     ┃┫┫
//        ┗┻┛     ┗┻┛
//
// ━━━━━━感觉萌萌哒━━━━━━

// Author        : WhyWhy
// Created Time  : 2015年07月20日 星期一 08时55分13秒
// File Name     : 1054.cpp

#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>
#include <time.h>

using namespace std;

const int MaxN=5005;

int R,C;
short dp[MaxN][MaxN];
int N;

struct Point
{
    int x,y;

    bool operator < (const Point &b) const
    {
        if(x==b.x)
            return y<b.y;

        return x<b.x;
    }
}P[MaxN];

inline bool in(int x,int y)
{
    return x<=R && x>=1 && y<=C && y>=1;
}

const int HASH=1000003;

struct HASHMAP
{
    int head[HASH],next[MaxN],Hcou;
    unsigned long long key[MaxN];
    int rem[MaxN];

    void init()
    {
        Hcou=0;
        memset(head,-1,sizeof(head));
    }

    void insert(unsigned long long val,int id)
    {
        int h=val%HASH;

        for(int i=head[h];i!=-1;i=next[i])
            if(val==key[i])
                return;

        rem[Hcou]=id;
        key[Hcou]=val;
        next[Hcou]=head[h];
        head[h]=Hcou++;
    }

    int find(unsigned long long val)
    {
        int h=val % HASH;

        for(int i=head[h];i!=-1;i=next[i])
            if(val==key[i])
                return rem[i];

        return 0;
    }
}map1;

int dfs(int u,int v)
{
    if(dp[u][v])
        return dp[u][v];

    int dx=(P[v].x<<1)-P[u].x,dy=(P[v].y<<1)-P[u].y;

    if(!in(dx,dy))
        return 2;

    int rP=map1.find(dx*10000+dy);

    if(!rP)
    {
        dp[u][v]=-1;
        return -1;
    }

    dp[u][v]=dfs(v,rP)+1;

    return dp[u][v];
}

inline bool judge(int u,int v)
{
    int dx=(P[u].x<<1)-P[v].x,dy=(P[u].y<<1)-P[v].y;

    return !in(dx,dy);
}

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

    int ans=-100;

    scanf("%d %d",&R,&C);
    scanf("%d",&N);

    for(int i=1;i<=N;++i)
        scanf("%d %d",&P[i].x,&P[i].y);

    sort(P+1,P+N+1);

    map1.init();

    for(int i=1;i<=N;++i)
        map1.insert(10000*P[i].x+P[i].y,i);

    for(int i=1;i<=N;++i)
        for(int j=i+1;j<=N;++j)
            if(judge(i,j))
                ans=max(ans,dfs(i,j));

    if(ans<3)
        ans=0;

    printf("%d\n",ans);

    return 0;
}

时间: 2024-11-05 12:15:52

(中等) POJ 1054 The Troublesome Frog,记忆化搜索。的相关文章

poj 1054 The Troublesome Frog (暴力搜索 + 剪枝优化)

题目链接 看到分类里是dp,结果想了半天,也没想出来,搜了一下题解,全是暴力! 不过剪枝很重要,下面我的代码 266ms. 题意: 在一个矩阵方格里面,青蛙在里面跳,但是青蛙每一步都是等长的跳, 从一个边界外,跳到了另一边的边界外,每跳一次对那个点进行标记. 现在给你很多青蛙跳过后的所标记的所有点,那请你从这些点里面找出 一条可能的路径里面出现过的标记点最多. 分析:先排序(目的是方便剪枝,break),然后枚举两个点,这两个 点代表这条路径的起始的两个点.然后是三个剪枝,下面有. 开始遍历时,

POJ - 1054 The Troublesome Frog

题意:给你个矩阵,里面有n个标记的点,许多只青蛙在上面跳,每次跳的距离都是一样的且轨迹是直线,目标是从一边跳到另一边,求最多步数的青蛙 思路:排序后,枚举判断 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 5050; struct point{ int x,y; void i

POJ 1054 The Troublesome Frog(枚举+剪枝)

题目链接 题意 :给你r*c的一块稻田,每个点都种有水稻,青蛙们晚上会从水稻地里穿过并踩倒,确保青蛙的每次跳跃的长度相同,且路线是直线,给出n个青蛙的脚印点问存在大于等于3的最大青蛙走的连续的脚印个数. 思路 : 暴力了一下,顺便剪剪枝就可以过.... 1 //POJ1054 2 #include <stdio.h> 3 #include <string.h> 4 #include <iostream> 5 #include <algorithm> 6 7

POJ 1351 Number of Locks (记忆化搜索 状态压缩)

Number of Locks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 1161   Accepted: 571 Description In certain factory a kind of spring locks is manufactured. There are n slots (1 < n < 17, n is a natural number.) for each lock. The height

POJ 3249 Test for Job (记忆化搜索 好题)

Test for Job Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 9512   Accepted: 2178 Description Mr.Dog was fired by his company. In order to support his family, he must find a new job as soon as possible. Nowadays, It's hard to have a job

poj 1661 Help Jimmy(记忆化搜索)

题目链接:http://poj.org/problem?id=1661 一道还可以的记忆化搜索题,主要是要想到如何设dp,记忆化搜索是避免递归过程中的重复求值,所以要得到dp必须知道如何递归 由于这是个可以左右移动的所以递归过程肯定设计左右所以dp的一维为从左边下或者从右边下,而且和层数有关所以另一维为层数 于是便可以得到dp[count][flag],flag=1表示count层从左边下要多久,flag=0表示count层从右边下要多久.然后就是dfs的递归 过程 #include <iost

poj 1579(动态规划初探之记忆化搜索)

Function Run Fun Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17843   Accepted: 9112 Description We all love recursion! Don't we? Consider a three-parameter recursive function w(a, b, c): if a <= 0 or b <= 0 or c <= 0, then w(a, b

POJ 1351-Number of Locks(记忆化搜索)

Number of Locks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 1140   Accepted: 559 Description In certain factory a kind of spring locks is manufactured. There are n slots (1 < n < 17, n is a natural number.) for each lock. The height

poj 1088 动态规划+dfs(记忆化搜索)

滑雪 Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道载一个 区域中最长底滑坡.区域由一个二维数组给出.数组的每个数字代表点的高度.下面是一个例子 1 2 3 4 5 16 17 18 19 6