Frog HDU - 5037 ( 贪心 )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SEVENY_/article/details/83216256

Frog 

Once upon a time, there is a little frog called Matt. One day, he came to a river. 

The river could be considered as an axis.Matt is standing on the left bank now (at position 0). He wants to cross the river, reach the right bank (at position M). But Matt could only jump for at most L units, for example from 0 to L. 

As the God of Nature, you must save this poor frog.There are N rocks lying in the river initially. The size of the rock is negligible. So it can be indicated by a point in the axis. Matt can jump to or from a rock as well as the bank. 

You don't want to make the things that easy. So you will put some new rocks into the river such that Matt could jump over the river in maximal steps.And you don't care the number of rocks you add since you are the God. 

Note that Matt is so clever that he always choose the optimal way after you put down all the rocks.

Input

The first line contains only one integer T, which indicates the number of test cases. 

For each test case, the first line contains N, M, L (0<=N<=2*10^5,1<=M<=10^9, 1<=L<=10^9). 

And in the following N lines, each line contains one integer within (0, M) indicating the position of rock.

Output

For each test case, just output one line “Case #x: y", where x is the case number (starting from 1) and y is the maximal number of steps Matt should jump.

Sample Input

2
1 10 5
5
2 10 3
3
6

Sample Output

Case #1: 2
Case #2: 4

题意:

有一条长为m的小河,可以看作一维坐标x轴,小河里存在n个石头,有一个每次最远能跳L米的青蛙,随意添加石头保证青蛙能从头跳到尾的,即从0调到m,问青蛙使用最优策略跳到对岸最多需要多少次。

开始我并没有很在意所说的青蛙使用最优策略,一看这个题就觉得,那就把x轴上每个点都放上石头,每次直跳1米,那不就是最多次了吗。哇这个想法太搞笑了。最优策略意思就是每次青蛙都会尽可能的跳到最远的那块石头。当然跳的距离肯定是在[1,L]区间范围内。

方法一:

一位Z大佬讲解的,我觉得比较好懂。崇拜佩服。

每次青蛙最远就是跳L米,那么我们就可以让青蛙在L+1的长度上跳两次是最优的。

pos是当前的位置,lastpost是上一次的位置。

那么每次就会有两种情况,第一种情况就是从当前的位置pos能够跳到下一个位置。那么就直接跳过去。


第二种情况就是从当前的位置pos不能直接跳到下一个位置,需要加入石头。

那么我们就要考虑最优的状态就是L+1的长度上跳两次。更新跳完之后的位置pos,和上一个位置lastpos。

然后我们再循环判断当前的位置pos属于哪一种情况。

代码:

#include<cstdio>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<algorithm>
#define N 300000
using namespace std; 
int a[N];
int main()
{ 
    int T;
    scanf("%d", &T);
    int p = 1;
    while(T -- )
    { 
        memset(a, 0, sizeof(a));
        int n, m, l;
        scanf("%d%d%d", &n, &m, &l);
        for(int i = 1; i <= n; i ++)
            scanf("%d", &a[i]);
        sort(a + 1, a + n + 1);
        a[n + 1] = m;
        a[n + 2] = 2100000000;
        int pos = 0; int lastpos = -l;
        int cnt = 0;
        for(int i = 1; i <= n + 1; i ++)
        { 
            if( a[i] - pos <= l && a[i + 1] - pos > l)//如果能直接跳到下一块石头 
            {
                lastpos = pos;
                pos = a[i];
                cnt ++;
            }
            else if( a[i] - pos > l)//如果不能直接跳到下一块石头(需要放石头) 
            {
                int x = (a[i] - pos) % (l + 1);
                int y = (a[i] - pos) / (l + 1);

                cnt = cnt + 2 * y;
                pos = a[i] - x -(pos - lastpos); //更新当前位置
                lastpos = a[i] - x - (l + 1);//更新上一个位置
                cnt --;
                i --;
            }
        }
        printf("Case #%d: %d\n", p++, cnt);
    }
}

方法二:

既然每次青蛙最远就是跳L米,那么我们就可以让青蛙在L+1的长度上跳两次是最优的,那么要想让它这么跳,在L+1处肯定需要有一块石头,L+1处的这块石头就是下一个L+1开始的0点。那么在[0,L+1]之间肯定也需要放一块石头,但是要考虑到前面青蛙已经跳到的位置,因为我们是希望它只能从0的位置开始跳的,如果(前面的位置到跳到的石头的距离)last+x(这段距离多出来的部分)<L+1的话,那么青蛙就可以在last+x之间跳一次;如果前面的位置到现在的距离last+x>=L+1,那么就需要跳两次。

从0到a[1]之间有y1个L+1,我们可以放入石头让青蛙在y1(L+1)中跳2*y1次,还有一块剩下的距离x1,青蛙也要从s1的位置再跳一次到a[1]处。  所以从0——>a[1]跳了(y1+1)次。

从a[1]到a[2]之间有y2个L+1,在y2(L+1)中我们可以让青蛙跳2*y2次,到a[2]还剩下x2的距离,那么我们就可以转换一下:

计算x1+x2的大小,如果x1+x2<L+1,那么青蛙就可以直接从s1跳一次跳到s2;从0——>a[2]跳了(y1+y2+1)次。

如果x1+x2>=L+1,那么青蛙从s1到s2就需要跳两次。从0——>a[2]跳了(y1+y2+2)次。

假设x1+x2<L+1。从从0——>a[2]跳了(y1+y2+1)次。从a[2]到a[3]之间有y3个L+1,在y3(L+1)中我们可以让青蛙跳2*y3次,到a[3]还剩下x3的距离,转换:

再次判断如果x1+x2+x3<L+1,那么青蛙就可以直接从一次跳过x1+x2+x3;从0——>a[3]跳了(y1+y2+y3+1)次。

如果x1+x2+x3>=L+1,那么青蛙从在x1+x2+x3之间就需要跳两次。从0——>a[3]跳了(y1+y2+y3+2)次。

……………………

 感觉会非常不好懂!!希望我能找到更通俗易懂的讲法。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[200007];
const int inf=(int)1e10;
int main()
{
	int t;
	scanf("%d",&t);
	for(int k=1;k<=t;k++)
	{ 
		int n,m,l;
		scanf("%d%d%d",&n,&m,&l);
		for(int i=1;i<=n;i++)
		 scanf("%d",&a[i]);
		a[0]=0;
		a[n+1]=m;
		int ans=0; //跳的次数 
		int last=l;
		sort(a,a+n+1);
		for (int i = 1; i<=n+1; i++) {
			int x = (a[i]-a[i-1]) % (l+1);//两块石头之间减去(L+1)的倍数后剩下的距离 
			int y = (a[i]-a[i-1]) / (l+1);//两块石头之间(L+1)的个数 
			if (last+x>=l+1) { //last+x:上一段区间剩下的距离+现在区间剩下的距离
				last=x;
				ans+=2*y+1;
			}
			else if (last+x<l+1) {
				last=last+x;
				ans+=2*y;
			}
		} 
		printf("Case #%d: %d\n",k,ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/SEVENY_/article/details/83216256