POJ1054 The Troublesome Frog

题意描述

The Troublesome Frog

给出一张 \(R\times C\) 网格图,其中 \(N\) 个节点上有标记。

求一条路径,使得路径上每个标记的间隔距离都相等的情况下,标记的数量最多,且至少为 \(3\) 个。

其中每条路径还需要保证向两端扩展一个间隔后将扩出网格图。

输出标记数量的最大值,如果得不出答案,输出 0

其中 \(1\leq R,C\leq 5000,3\leq N\leq 5000\)

算法分析

枚举+剪枝。

首先将节点从左上到右下排序。

然后暴力枚举两两节点当做路径的起始节点第二节点,并暴力向前扩展。

最坏时间复杂度 \(O(N^3)\),不难发现无法通过此题。

剪枝一:可行性剪枝

根据题目意思:每条路径还需要保证向两端扩展一个间隔后将扩出网格图

我们可以在开始扩展前就判断是否能扩出图外。

在扩展结束后再判断一次是否能扩出图外。

其实这可以说是按照题意排除错误答案,不算做传统意义上的剪枝。

剪枝二:最优化剪枝

这是一个很强的剪枝。

我们假设当前得到的答案为 \(ans\)

显然如果当前枚举的两个节点所构成的道路上的总结点数 \(\leq ans\),就可以直接剪枝。

具体判断方法看之后的代码。

时间复杂度

由于有了上面两个剪枝,特别是第二个剪枝,导致找到答案之后的所有枚举几乎全都被剪枝了。

所以时间复杂度趋向于 \(O(N^2)\),实测跑得飞快。

代码实现

实现复杂度较为简单,注意边界的判断。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> 
#define N 5010
#define INF 0x3f3f3f3f
using namespace std;

int r,c,n;
bool mp[N][N];
struct node{int x,y;}a[N];

int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
    return x*f;
}

bool cmp(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;}

int main(){
	//freopen("frog.in","r",stdin);
	//freopen("frog.out","w",stdout);
	r=read(),c=read(),n=read();
	for(int i=1;i<=n;i++){
		a[i].x=read(),a[i].y=read();
		mp[a[i].x][a[i].y]=true;
	}
	sort(a+1,a+n+1,cmp);
	int ans=0;
	for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++){
			int dx=a[j].x-a[i].x;
			int dy=a[j].y-a[i].y;
			int prex=a[i].x-dx;
			int prey=a[i].y-dy;
			if(prex>=1 && prex<=r && prey>=1 && prey<=c) continue;
			
			int nowx=a[j].x+ans*dx;
			int nowy=a[j].y+ans*dy;
			if(!(nowx>=1 && nowx<=r && nowy>=1 && nowy<=c)) continue;

			int now=0;
			nowx=a[j].x,nowy=a[j].y;
			while(1){
				nowx+=dx;nowy+=dy;
				if(!(nowx>=1 && nowx<=r && nowy>=1 && nowy<=c)) break;
				if(!mp[nowx][nowy]) break;
				now++;
			}
			if(nowx>=1 && nowx<=r && nowy>=1 && nowy<=c) now=0;
			ans=max(ans,now);
		}
	printf("%d\n",ans==0?0:ans+2);
	return 0;
}
posted @ 2021-02-25 20:15  LPF'sBlog  阅读(69)  评论(0编辑  收藏  举报