POJ1054 The Troublesome Frog

The Troublesome Frog
Time Limit: 5000MS Memory Limit: 100000K
Total Submissions: 11772 Accepted: 3538
Case Time Limit: 500MS

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. 

Input

Your program is to read from standard input. The first line contains two integers R and C, respectively the number of rows and columns in your rice paddy, 1 <= R,C <= 5000. The second line contains the single integer N, the number of flattened rice plants, 3 <= N <= 5000. Each of the remaining N lines contains two integers, the row number (1 <= row number <= R) and the column number (1 <= column number <= C) of a flattened rice plant, separated by one blank. Each flattened plant is only listed once.

Output

Your program is to write to standard output. The output contains one line with a single integer, the number of plants flattened along a frog path which did the most damage if there exists at least one frog path, otherwise, 0.

Sample Input

6 7
14
2 1
6 6
4 2
2 5
2 6
2 7
3 4
6 1
6 2
2 3
6 3
6 4
6 5
6 7

Sample Output

7

Source



//刚做 想了许久 最后两点确定一条直线(根据两点的间距去试探如果在地图里但有没被踩证明这条线不行)
// 没排序 直接两边搜 还加了个 map 优化 但是没什么卵用 TE

#include<stdio.h>
#include<string.h>
#include<map>
#include<string>
#include<algorithm>
using namespace std;
bool ap[5001][5001];

struct node
{
    int x;
    int y;
} plants[5005];

int n,m;
int pd(int x,int y)
{
    if(x<1||x>n||y<1||y>m)
        return 1;
    return 0;
}

int main()
{
    int h,j,i,ans,a,b,MAX,u1,w1,u2,w2,k,g,x,y,flag;
    string str;
    scanf("%d%d",&n,&m);
    scanf("%d",&h);

    map<string,int>Q;
    memset(ap,0,sizeof(ap));
    for(i=0; i<h; i++)
        {scanf("%d%d",&a,&b);
        ap[a][b]=1;
          plants[i].x=a;
          plants[i].y=b;
        }
    MAX=0;
    for(i=0; i<h-2; i++)
        for(j=i+1; j<h-1; j++)
        {
            x=plants[i].x-plants[j].x;
            y=plants[i].y-plants[j].y;
            u2=u1=plants[i].x;
            w2=w1=plants[i].y;
            str.clear();
                str+=u1+'0';
                str+=w1+'0';
                u1+=x;
                w1+=y;
                str+=u1+'0';
                str+=w1+'0';
               if(Q.find(str)!=Q.end()) continue;
               str.clear();
                str+=u1+'0';
                str+=w1+'0';
                u1-=x;
                w1-=y;
                str+=u1+'0';
                str+=w1+'0';
                if(Q.find(str)!=Q.end()) continue;
            ans=1;
            flag=0;
            while(1)
            {
                str.clear();
                str+=u1+'0';
                str+=w1+'0';
                u1+=x;
                w1+=y;
                str+=u1+'0';
                str+=w1+'0';
                Q[str]=1;
                if(pd(u1,w1))  break;
                if(!pd(u1,w1)&&ap[u1][w1]==0)
                {
                    flag=1;
                    break;
                }
                if(ap[u1][w1]==1) ans++;
            }
            if(flag==1) continue;
            while(1)
            {
                str.clear();
                str+=u2+'0';
                str+=w2+'0';
                u2-=x;
                w2-=y;
                str+=u2+'0';
                str+=w2+'0';
                Q[str]=1;
                if(pd(u2,w2))  break;
                if(!pd(u2,w2)&&ap[u2][w2]==0)
                {
                    flag=1;
                    break;
                }
                if(ap[u2][w2]==1) ans++;
            }

            if(flag==1) continue;
            if(ans>MAX) MAX=ans;
        }

    if(MAX>2) printf("%d\n",MAX);
    else printf("0\n");
    return 0;
}

剪枝过的 直接标记 (没用二分搜索的时候)
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <math.h>
using namespace std;
struct bode
{
    int x,y;
} node[5005];
bool vis[5005][5005];
int n,disx,disy,r,c,tmpx,tmpy,max1=0,cnt;
int cmp(const bode &a,const bode &b)
{
    if(a.y==b.y)return a.x<b.x;
    else return a.y<b.y;
}
int main()
{
    scanf("%d%d",&r,&c);
    scanf("%d",&n);
    memset(vis,false,sizeof(vis));
    for(int i=0; i<n; i++)
    {
        scanf("%d%d",&node[i].x,&node[i].y);
        vis[node[i].x][node[i].y]=true;  //标记
    }
    sort(node,node+n,cmp);
    max1=0;
    for(int i=0;i<n;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            disx=node[j].x-node[i].x;
            disy=node[j].y-node[i].y;
            if(node[i].x-disx>0&&node[i].x-disx<=r&&node[i].y-disy>0&&node[i].y-disy<=c) //剪枝
                continue;
            tmpx=node[j].x+disx;
            tmpy=node[j].y+disy;
            cnt=0;
            while(tmpx>0&&tmpx<=r&&tmpy>0&&tmpy<=c)
            {
                if(vis[tmpx][tmpy])cnt++;      
                else
                {
                    cnt=0;
                    break;
                }
                tmpx+=disx;
                tmpy+=disy;
            }
            max1=max(max1,cnt);
        }
    }
    if(max1)
        printf("%d\n",max1+2);
    else puts("0");
    return 0;
}

最优的
#include<stdio.h>
#include<stdlib.h>
using namespace std;
struct PLANT
{
    int x;
    int y;
} plants[5005];
int n,m,h;

int searchpath(PLANT plant,int dx,int dy);
int cmp(const void *ele1,const void *ele2);

int main()
{
    int i,j,dx,dy,px,py;
    scanf("%d%d",&n,&m);
    scanf("%d",&h);
    for(i=0; i<h; i++)
        scanf("%d%d",&plants[i].x,&plants[i].y);
    qsort(plants,h,sizeof(PLANT),cmp);
    int MAX=2,steps;
    for(i=0; i<h-2; i++)
        for(j=i+1; j<h-1; j++)
        {
            dx=plants[j].x-plants[i].x;
            dy=plants[j].y-plants[i].y;
            px=plants[i].x-dx;
            py=plants[i].y-dy;
            if(px>0&&px<=n&&py>0&&py<=m)  //判断前一个点是不是在地图里 如果在就不需要再进行下去
                continue;                  // 前面已经访问过了 在访问也不可能有前面的长
            if(plants[i].x+MAX*dx>n) //剪枝 这一层直接(越到后面越不可能)
                break;
            py=plants[i].y+MAX*dy;
            if(py<1||py>m)
                continue ;
            steps=searchpath(plants[j],dx,dy);
            if(steps>MAX) MAX=steps;
        }
    if(MAX>2) printf("%d\n",MAX);
    else printf("0\n");
    return 0;
}

int  cmp(const void *ele1,const void *ele2)
{
    PLANT *p1,*p2;
    p1=(PLANT*)ele1;
    p2=(PLANT*)ele2;
    if(p1->x==p2->x) return (p1->y - p2->y);
    return (p1->x - p2->x );
}

int searchpath( PLANT plant, int dx, int dy )
{
    int steps = 2;
    plant.x+=dx;
    plant.y+=dy;
    while ( plant.x <= n&& plant.x >= 1 && plant.y <= m && plant.y >= 1 )
    {
        if ( !bsearch(&plant, plants, h, sizeof(PLANT), cmp) )
        {
            steps = 0;
            break;
        }
        plant.x += dx;
        plant.y += dy;
        steps++;
    }
    return steps;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值