1326. 灌溉花园的最少水龙头数目----cpp解法思路

解法一:贪心

思路:每次选一个区间,区间右端可以覆盖当前需要覆盖的最右端,同时该区间能覆盖的最左侧点索引最小。
代码
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>

using namespace std;

//用于sort函数排序,先根据区间右端排序,再根据区间左端排序
static bool cmp(vector<int>& pre, vector<int>& next){
    return pre[1]<next[1] || (pre[1]==next[1] && pre[0]>next[0]);
}

int solution(int n, vector<vector<int> > intervals){

    //都已经被灌溉,返回0
    if(n == 0){
        return 0;
    }
    
    //点n无法被灌溉,返回-1
    int len = intervals.size();
    if(len == 0 || intervals[len-1][1] < n){
        return -1;
    }

    int left = intervals[len-1][0];
    int index = len-1;
    while(index>=0){
        //找出可以所有可以灌溉到点n的区间里,可以灌溉到的最左端点的索引
        if(intervals[index][1] >= n){
            if(intervals[index][0]<left){
                left = intervals[index][0];
            }
            index--;
        }else{
            break;
        }
    }

    vector<vector<int> > nextIntervals(intervals.begin(), intervals.begin() + index +1);

    int nextValue = solution(left, nextIntervals);
    //子迭代中有点无法被灌溉到,返回-1
    if(nextValue == -1){
        return -1;
    }
    //子迭代中所有点被灌溉到,返回nextValue+1
    return nextValue+1;
}
//贪心:每次选一个区间,区间右端可以覆盖当前需要覆盖的最右端,同时该区间能覆盖的最左侧点索引最小
int minTaps(int n, vector<int>& ranges) {
    vector<vector<int> > intervals;

    vector<int>::iterator iter = ranges.begin();
    while (iter != ranges.end())
    {
        //将可以喷水的水龙头可以灌溉的区域用区间表示
        if(*iter !=0){
            vector<int> internal(2, 0);
            int r= *iter;
            int center = iter-ranges.begin();
            //cout<<"center:"<<center<<" r:"<<r<<endl;
            internal[0] = max(center-r, 0);
            internal[1] = min(center+r, n);
            //cout<<"["<<internal[0]<<", "<<internal[1]<<"]"<<endl;
            intervals.push_back(internal);
        }
        iter++;
    
    }
    //将区间排序,先根据区间右端排序,再根据区间左端排序
    sort(intervals.begin(), intervals.end(), cmp);
    // cout<<"sort:"<<endl;
    // for(vector<vector<int> >::iterator i=intervals.begin();i!=intervals.end();i++){
    //     cout<<"["<<(*i)[0]<<" ,"<<(*i)[1]<<"]"<< endl;
    // }
    return solution(n, intervals);
}



int main(){
    // int arr[] = {1,2,1,0,2,1,0,1};
    // int n =7;
    // vector<int> test(arr, arr+sizeof(arr)/sizeof(int));
    // cout<< minTaps(n, test) <<endl;
    // int arr[] = {2,0,0,0};
    // int n =3;
    // vector<int> test(arr, arr+sizeof(arr)/sizeof(int));
    // cout<< minTaps(n, test) <<endl;

    int arr[] = {1,0,4,0,4,1,4,3,1,1,1,2,1,4,0,3,0,3,0,3,0,5,3,0,0,1,2,1,2,4,3,0,1,0,5,2};
    int n =35;
    vector<int> test(arr, arr+sizeof(arr)/sizeof(int));
    cout<< minTaps(n, test) <<endl;

}
解法二:有点像投票:每个需要被灌溉的点,选取一个水龙头,该水龙头可以灌溉到该点,同时是所以可以灌溉到该点的水龙头中,右侧能覆盖到的点索引最大的水龙头
代码
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>

using namespace std;

//有点像投票:每个需要被灌溉的点,选取一个水龙头,该水龙头可以灌溉到该点,
//同时是所以可以灌溉到该点的水龙头中,右侧能覆盖到的点索引最大的水龙头
int minTaps(int n, vector<int>& ranges){
    vector<int> covered(n+1, 0);

    for(int i=0;i<=n;i++){
        if(ranges[i] == 0){
            continue;
        }

        int l=max(0, i-ranges[i]);
        int r=min(n, i+ranges[i]);

        for(int j=l;j<=r;j++){
            covered[j] = max(covered[j], r);
        }
    }

    int index = 0;
    int step = 0;
    while(index<=n){
        if(index == n){
            break;
        }
        //有点无法被灌溉
        if(covered[index] == 0 || (covered[index]<n && covered[covered[index]] == covered[index])){
            return -1;
        }
        index = covered[index];
        step++;
    }
    return step;
}

int main(){
    // int arr[] = {1,2,1,0,2,1,0,1};
    // int n =7;
    // vector<int> test(arr, arr+sizeof(arr)/sizeof(int));
    // cout<< minTaps(n, test) <<endl;
    // int arr[] = {2,0,0,0};
    // int n =3;
    // vector<int> test(arr, arr+sizeof(arr)/sizeof(int));
    // cout<< minTaps(n, test) <<endl;

    int arr[] = {1,0,4,0,4,1,4,3,1,1,1,2,1,4,0,3,0,3,0,3,0,5,3,0,0,1,2,1,2,4,3,0,1,0,5,2};
    int n =35;
    vector<int> test(arr, arr+sizeof(arr)/sizeof(int));
    cout<< minTaps(n, test) <<endl;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值