2020-2-2摸底测试B 贪心

题面:

Vova's house is an array consisting of n elements (yeah, this is the first problem, I think, where someone lives in the array). There are heaters in some positions of the array. The i-th element of the array is 1 if there is a heater in the position i, otherwise the i-th element of the array is 0

.

Each heater has a value r

(r is the same for all heaters). This value means that the heater at the position pos can warm up all the elements in range [pos−r+1;pos+r−1]

.

Vova likes to walk through his house while he thinks, and he hates cold positions of his house. Vova wants to switch some of his heaters on in such a way that each element of his house will be warmed up by at least one heater.

Vova's target is to warm up the whole house (all the elements of the array), i.e. if n=6

, r=2 and heaters are at positions 2 and 5, then Vova can warm up the whole house if he switches all the heaters in the house on (then the first 3 elements will be warmed up by the first heater and the last 3

elements will be warmed up by the second heater).

Initially, all the heaters are off.

But from the other hand, Vova didn't like to pay much for the electricity. So he wants to switch the minimum number of heaters on in such a way that each element of his house is warmed up by at least one heater.

Your task is to find this number of heaters or say that it is impossible to warm up the whole house.

Input

The first line of the input contains two integers n

and r (1≤n,r≤1000

) — the number of elements in the array and the value of heaters.

The second line contains n

integers a1,a2,…,an (0≤ai≤1

) — the Vova's house description.

Output

Print one integer — the minimum number of heaters needed to warm up the whole house or -1 if it is impossible to do it.

吐了,题面复制过来太惨了,就这样吧不修复了。

题目大意:

一个数组,里面有某些元素为1,其他为0,为1的元素可以点亮算上该元素左右各r个元素,问:要使整个数组都被照亮至少需要打开多少个1元素?数组长度和r<=103

 

思路:贪心。怎么贪?枚举每个需要被点亮的房间,找尽可能靠右的1元素点亮它,如果找不到直接打印-1返回

 

代码如下:

#include <cstdio>
int N,r,a[2001],ans;
int main(){
    scanf("%d%d",&N,&r);
    for(int i=1;i<=N;i++)scanf("%d",&a[i]);
    int pos=1; 
    while(pos<=N){
        int index=0;
        for(int i=1;i<=N;i++)
            if(a[i]&&pos>=i-r+1&&pos<=i+r-1)
                index=i;
        if(!index){
            printf("-1");
            return 0;
        }
        ans++;
        pos=index+r;//直接跳到那个1元素能点亮的最右边的下一个位置
    }
    printf("%d",ans);
    return 0;
}

让我复盘一下当时的错误思路:

当时我第一反应就是,这玩意儿不是个贪心就是个DP,但贪心我是真的不会,看看能不能DP解(上来就走错方向了呜呜呜)

然后,我就开始想:DP一定要确定问题,然后找到最优子结构,这样就解出来了。

显然,问题就是点亮元素1-n,并且使用最少的加热器(对不起我还是用了原文,这里“加热器”就是上面的“1元素”)

我当时是倒着想的,如果想要点亮1-n,那么必然要点亮1- n-1,那么我就可以构建状态转移方程:f[n]=g(f[n-1])

对,就是错这里了。因为我的思路没有满足无后效性。就是说,在点亮前n-1个元素的时候,选择不同的加热器组会导致“向右溢出”不同的点亮范围。

 

总结:

对于这道题,我个人感觉似曾相识,首先他是个线性DP,其次,每个加热器是“对左右都起效的”。类似这样的题目,根据本题题解,我想,解决思路应该是“从左扫,向右贪”。意思就是:从左往右扫来保证当前点左边的点都是“可行“或者说”合法”的,在此基础上找到最右边能对当前点生效的那个“加热器”。

上一篇:2014-hack-lu-oreo 对技巧house of spirit


下一篇:Tornado WEB服务器框架 Epoll-- 【2】