您的位置:首页 > 其它

UVALive 3610 Log Jumping(贪心)

2017-03-21 15:20 302 查看
题目链接:点击打开链接

刘汝佳的大白书里面对这道题的归类是可转化为经典问题的DP,但是死活想不出来怎么dp。

反倒是想到了一种类似贪心的思路。

首先,我们可以把跳的路线看做是一个环,并把跳跃的顺序强制规定为【从最左边往右跳到最右边再往左跳】。

初步思路是对木头的左端点排序,然后枚举最左的木头,之后维护上下两个端点(木头)进行dp,就跟双调欧几里得旅行商问题一样。

但是这么做的话时间复杂度为O(n^3),显然不行。

后来发现完全没有这个必要。当你知道最左的木头的时候其实就可以由贪心的策略得到其最长的长度了。

首先当然也是排序,对木头的左端点升序排序。

对于已确定的左端点,分两种情况:

1. 它跳不到下一条木头,那么答案就为1。

2. 它跳的到下一条木头,那么这条木头就默认作为在维护的【环】中的上端点,原来那个就是下端点。于是就可以继续往下扫过去,每条被扫到的木头都放到跟上下端点中的最左的那条相接的位置【也就是说,由上下端点中的最左的那条跳往这一条】,并更新新的端点。

而对于第二步,由于每条木条的长度是一样的,也就是说当上端点被更新之后必定是下端点最左,反之就是上端点最左。

于是我们就可以默认在这种情况下第i条必定由第i-2条跳过去。

枚举然后扫一边就行了,复杂度O(n^2)。

代码如下:

#include<bits/stdc++.h>
#define INF 10000000
using namespace std;

int a[5005];

int n,len;

inline bool check(int i,int j)
{
return a[i]+len>=a[j];
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&len);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int ans=1;
for(int i=0;i<n;i++)
{
if(n-i<=ans)break;
int pans=1;
if(check(i,i+1))pans++;
else continue;
for(int j=i+2;j<n;j++)
{
if(check(j-2,j))pans++;
else break;
}
ans=max(ans,pans);
}
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: