首页 > 试题广场 >

视野争夺

[编程题]视野争夺
  • 热度指数:8248 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小Q在进行一场竞技游戏,这场游戏的胜负关键就在于能否能争夺一条长度为L的河道,即可以看作是[0,L]的一条数轴。
这款竞技游戏当中有n个可以提供视野的道具−真视守卫,第i个真视守卫能够覆盖区间[xi,yi]。现在小Q想知道至少用几个真视守卫就可以覆盖整段河道。 

输入描述:
输入包括n+1行。

第一行包括两个正整数n和L(1<=n<=105,1<=L<=109)

接下来的n行,每行两个正整数xi,yi(0<=xi<=yi<=109),表示第i个真视守卫覆盖的区间。 



输出描述:
一个整数,表示最少需要的真视守卫数量, 如果无解, 输出-1。
示例1

输入

4 6
3 6
2 4
0 2
4 7

输出

3
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int L=in.nextInt();
		int[][] temp=new int[n][2];
		for(int i=0;i<n;i++) {
			for(int j=0;j<2;j++) {
				temp[i][j]=in.nextInt();
			}
		}
		//。获得了数组,进行排序
		Arrays.sort(temp,new Comparator<int[]>() {
			public int compare(int[] o1, int[] o2) {
				return o1[0]==o2[0]?o1[1]-o2[1]:o1[0]-o2[0];
			}
		});
		int index=0;
		int count=0;
		int pre=0;   //右边界
		while(pre<L) {
			if(temp[index][0]>pre) {
				System.out.println(-1);
			}
			int max=0;
			while(index<n&&temp[index][0]<=pre) {
				max=Math.max(max, temp[index][1]);
				index++;
			}
			count++;
			pre=max;
			if(pre>=L) {
				System.out.println(count);
                return;
			}
			if(index>=n) {
				System.out.println(-1);
                return;
			}
		}
	}
}
Java贪心算法
编辑于 2020-04-27 17:09:45 回复(4)
贪心策略
只需要右指针
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
 
int main(){
    int n,L;cin >> n >> L;
    vector<pair<int,int>> vec(n);
    for(int i=0;i<n;++i) cin >> vec[i].first >> vec[i].second;
    sort(vec.begin(),vec.end());
    if(vec[0].first>0) {cout << -1;return 0;}//teshuqingkuang
    int right = 0;
    int i = 0;
    int res = 0;
    while(i<n){
        int r = right;
        for(;i<n && vec[i].first<=r;++i){
            right = max(right,vec[i].second);
        }
        ++res;
        if(right>=L) {cout << res;return 0;}
        if(i>=n || vec[i].first>right) {cout << -1;return 0;}
    }
    return 0;
  
}


编辑于 2020-04-23 00:09:49 回复(5)
Python 483ms 贪心
O(nlogn),排序,遍历一遍
1. 按照区间start排序
2. 在start <= pre_end的所有区间中找到最大的结束点,选择该区间,res += 1。(如果每次循环的第一个区间的start > pre_end,证明区间不连续,print (-1))
3. 重复2到结束
4. 如果pre_end < L,证明无法覆盖[0, L], print (-1),otherwise,print (res). 
代码如下:
import sys
n, L = [int(x) for x in input().strip().split()]
regions = []
for row in sys.stdin:
    regions.append([int(x) for x in row.strip().split()])

regions.sort(key=lambda x: x[0])
pre_end = 0
res = 0
i = 0
while i < len(regions):
    if regions[i][0] > pre_end:
        res = -1
        break
    k = i + 1
    cur_end = regions[i][1]
    while k < len(regions) and regions[k][0] <= pre_end:
        cur_end = max(cur_end, regions[k][1])
        k += 1
    pre_end = cur_end
    i = k
    res += 1
    if pre_end >= L:
        break
if pre_end < L:
    res = -1
print(res)


发表于 2022-03-29 06:28:42 回复(0)
//贪心选择
n,L = map(int,input().split())
xy = []
for _ in range(n):
    xy.append(list(map(int,input().split())))
xy.sort(key = lambda x : x[0])
last = 0//当前已选尾部位置
max_reach = 0//当前可选最大到达位置
cnt = 1//ans 先加最后一个
for i in range(n):
    if max_reach >=L:break//一定要加,不然初始化1可能会重复
    if xy[i][0]>max_reach:
        print(-1)
        exit()
    if xy[i][0]>last://此时需要更新last
        last = max_reach//确定选择max_reach
        cnt+=1
        max_reach = max(xy[i][1],max_reach)//勿忘更新max
        continue
    max_reach = max(xy[i][1],max_reach)//日常更新max
if max_reach >= L:
    print(cnt)
else:
    print(-1)
发表于 2020-04-06 22:55:00 回复(3)
通过案例只有60%, 各位路过的大佬指教一下, 实在找不出来有什么问题。。。
#include <bits/stdc++.h>
using namespace std;

int main()
{
    long long l, n;
    cin >> n;
    cin >> l;
    vector<pair<long long, long long>> data(n);
    for (int i = 0; i < n; i++)
    {
        cin >> data[i].first;
        cin >> data[i].second;
    }
    
    sort(data.begin(), data.end(), [](pair<long long, long long> left, pair<long long, long long> right)
         {
             if (left.first == right.first)
                 return left.second > right.second;
             else return left.first < right.first;
         });
    int res = 0;
    long long right = -1;
    int index = 0;
    while (right < l && index < n)
    {
        long long lastRight = right;
        
        //贪心 寻找可以到达的最远距离
        while (index < n && data[index].first <= lastRight + 1)
        {
            right = max(data[index].second, right);
            index++;
        }
        
        //无法到达比 lastRight更远的距离
        if (right == lastRight) break;
        
        //只要right更新 就代表又选择了 一个真视守卫
        res++;
    }
    if (right < l) cout << -1;
    else cout << res;
}


发表于 2021-03-16 16:50:10 回复(2)
#include <iostream>
#include <map>

using namespace std;

class Solution{
    public:
    void leastCoverdRiver(){
        multimap<int,int> nums;
        int n,L,a,b;
        cin>>n>>L;
        for(int i=0;i<n;i++){
            cin>>a>>b;
            nums.insert(multimap<int,int>::value_type(a,b));
        }
        if(L==0){
            cout<<-1<<endl;
            return;
        }
        int ans=1,l=0,r=nums.begin()->second;;//初始化已经有1个
        for(auto& num:nums){            
                  //判断左边界已经进入下一个阶段,需满足大于之前的边界
            if(l<num.first&&num.second>r){l=r;ans++;}
            if(num.first<=l&&num.second>r){//选出最大的右边界
                r=num.second;
            }
            if(r>=L) break;//满足条件退出
        }
        if(r>=L){//判断是否在该区域内
            cout<<ans<<endl;
        }else{
            cout<<-1<<endl;
        }

    }
};

int main(int argc,char* argv[]){
    Solution().leastCoverdRiver();
    return 0;
}

利用map即可,默认按照key升序排序,每次枚举记下右边界L最大值,并且判断是否在允许的左边界R内,若满足,则更新最大的右边界面,否则,则更新左边界,并进行计数。
编辑于 2021-03-09 17:55:56 回复(0)
import java.util.*;
 
public class Main {
 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int l = scanner.nextInt();
        PriorityQueue<int[]> queue = new PriorityQueue<>((o1, o2) -> {
            if (o1[0] == o2[0])
                return o2[1] - o1[1];
            return o1[0] - o2[0];
        });
        for (int i = 0; i < n; i++) {
            int[] arr = new int[2];
            arr[0] = scanner.nextInt();
            arr[1] = scanner.nextInt();
            queue.offer(arr);
        }
        scanner.close();
        if (queue.peek()[0] != 0) {
            System.out.println(-1);
        } else {
            int from = queue.poll()[1];
            int count = 1;
            PriorityQueue<int[]> queue1 = new PriorityQueue<>((o1, o2) -> o2[1] - o1[1]);
            while (from < l) {
                while (queue.size() > 0 && queue.peek()[0] <= from)
                    queue1.offer(queue.poll());
                if (queue1.size() > 0 && queue1.peek()[1] > from) {
                    from = queue1.poll()[1];
                    count++;
                } else {
                    System.out.println(-1);
                    return;
                }
            }
            System.out.println(count);
        }
    }
}

发表于 2020-04-02 21:53:16 回复(0)
import java.util.*;
public class Main{
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int l = in.nextInt();
        int[][] guard = new int[n][2];
        for (int i = 0;i < guard.length; ++i) {
            guard[i][0] = in.nextInt();
            guard[i][1] = in.nextInt();
        }
        Arrays.sort(guard, (a, b) -> a[0]-b[0]);
        if (guard[0][0] > 0) System.out.println(-1);
        int end = guard[0][1];
        int cnt = 1;
        int max = end;
        for (int i = 1;i < guard.length; ++i) {
            if (guard[i][0] <= end) {
                max = Math.max(max, guard[i][1]);
            } else {
                if (guard[i][0] > max)
                    System.out.println(-1);
                else {
                    end = max;
                    max = guard[i][1];
                    cnt++;
                }
            }
            if (end >= l) {
                System.out.println(cnt);
                return;
            }
        }
        if (end != max){
            end = max;
            cnt++;
        }
        if (end >= l) {
            System.out.println(cnt);
        } else {
            System.out.println(-1);
        }
    }
}

发表于 2020-04-02 20:21:49 回复(0)
力扣第172场周赛最后一题换个了壳.. 
# include <iostream>
# include <cstdlib>
# include <stack>
# include <cstring>
# include <unordered_map>
# include <vector>
# include <algorithm>
# define N 100100
# define inf 0x3f3f3f3f
using namespace std;
 
int n,L;
 
int main(void){
    while( cin>>n>>L ){
        vector<vector<int>> nums;
        int a,b;
        for ( int i=0; i<n; ++i ){
            cin>>a>>b;
            nums.push_back({a,b});
        }
        sort( nums.begin(), nums.end(), [](vector<int>&a, vector<int>&b){
            return a[0]<b[0] || (a[0]==b[0] && a[1]>b[1]);
        } );
        int pre = 0, i=0, ans=0, last=0;
        while( i<nums.size() ){
             
            while( i<nums.size() && nums[i][0]<=pre ){
                last = max(last, nums[i][1]);
                ++i;
            }
            ++ans;
            pre = last;
            if ( i<nums.size() && nums[i][0]>pre ){
                ans = -1;
                break;
            }
            if ( last>=L ) break;
             
        }
        if ( ans==-1 || last<L )
            cout<<-1<<endl;
        else cout<<ans<<endl;
    }
    return 0;
}


发表于 2020-02-12 00:08:48 回复(7)
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int L = in.nextInt();
        int[][] arr = new int[n][2];
        for(int i =0;i<n;i++){
            for(int j =0;j<2;j++){
                arr[i][j] = in.nextInt();
            }
        }
        
        //贪心思想,每次找右边值能覆盖最大范围,所用个数最小
        
        //按左边值排序
        Arrays.sort(arr, (int[] o1,int[] o2)-> o1[0]-o2[0]);

       int rowIndex = 1;
        
        int count = 1;
        //第一个值存起来,后面的遍历与这个比较
        int[] temp = arr[0];
        //保存右边值得最大值,
        int maxValue = temp[1];
        //如果开头不为0则返回-1
        if (temp[0] != 0){
            System.out.println(-1);
            return;
        }
        while(rowIndex<arr.length){
          //如果右边最大值超过L则说明覆盖完全,++count是因为要加上maxValue这个守卫
            if(maxValue >=L){
                System.out.println(++count);
                return;
            }
            //最开始的右边值覆盖不住左边值时,说明要换守卫,所以守卫加一,并更新右边值
            if(arr[rowIndex][0] > temp[1]){
                count++;
                temp[1] = maxValue;
            }else{
                maxValue = Math.max(maxValue,arr[rowIndex][1]);
                rowIndex++;
            }
        }
        //如果符合条件的在最后一个,则maxValue此时就是能够覆盖的值,所以需要再进行判断
        if(maxValue >=L){
            System.out.print(++count);
        }else{
            //如果都没有符合条件的值,同样会遍历完
            System.out.print(-1);
            
        }
        
        
    }
}

发表于 2022-06-17 21:11:00 回复(0)
package main

import "fmt"
import "sort"

func covered(nums [][]int, length int) int {
	sort.Slice(nums,func(i, j int) bool {
		if nums[i][0] == nums[j][0] {
			return nums[i][1] > nums[j][1]
		} else {
			return nums[i][0] < nums[j][0]
		}
	})
	pre_end := 0
	start := 0
	res := 0 
    for start < len(nums) {
        if nums[start][0] > pre_end {
            return -1
        }
        k := start + 1
        max := nums[start][1]
        for k < len(nums) && nums[k][0] <= pre_end {
            if max < nums[k][1] {
                max = nums[k][1]
            }
            k++
        }
        pre_end = max
        res++
        start = k
        if pre_end >= length {
            break
        }        
    }
    if pre_end < length {
        return -1
    }
	return res
}

func main() {
	var n, l int
	fmt.Scanln(&n,&l)
	var a,b int
	nums := [][]int{}
	for i := 0; i < n; i++ {
		fmt.Scanln(&a,&b)
		nums = append(nums, []int{a,b})
	}
	ans := covered(nums,l)
	fmt.Println(ans)
}
无论如何都只过60%是怎么回事啊?求大佬带教教我

发表于 2022-04-23 22:06:25 回复(0)

该题关键是要完全覆盖河道.

我们可以将覆盖区间的起始点从小到大排序, 若起始点相同,那么在根据结束点排序.

我们只需从左往右看, 在目前能到达的长度下, 尽可能挑选一个照的远的眼. 当眼的起始点已经超过目前能到达的长度时

  • 眼数 + 1

  • 目前能到达的长度 = 尽可能挑选一个照的远的眼的长度
        
    #include <algorithm>
    #include <iostream>
    #include <stack>
    #include <vector>
    using namespace std;
    
    
    class Solution {
    public:
    };
    
    struct Comparator {
      // 我们可以将覆盖区间的起始点从小到大排序, 若起始点相同,那么在根据结束点排序.
        bool operator()(pair<int, int> p1, pair<int, int> p2) {
            if (p1.first == p2.first)
                return p1.second < p2.second;
            else
                return p1.first < p2.first;
        }
    } comparator;
    
    int main() {
        int n, l;
        cin >> n >> l;
        pair<int, int> sections[100000];
        for (int i = 0; i < n; ++i) {
            cin >> sections[i].first >> sections[i].second;
        }
      	// 排序
        sort(sections, sections + n, comparator);
        int i = 0;
        int newLength = 0;
        // 去除被完全覆盖的区间 如 [0, 9], [0, 8]其中[0, 8]是不可能选择的, 要尽可能少买眼, 所以只用考虑照亮区间大的
        while (i < n) {
            int val = sections[i].first;
            while (val == sections[i].first) {
                ++i;
            }
            sections[newLength++] = sections[i - 1];
        }
      	// 若连最开始的眼都找不了开头, 那不可能完全覆盖
        if (sections[0].first > 0) {
            cout << "-1";
            return 0;
        }
      	// 更新区间数组长度
        n = newLength;
        i = 0;
      	// 要买的眼数
        int output = 0;
        // 未来可以到达的长度
        int tail = sections[0].second;
        // 目前可以到达的长度
        int last = -1;
        while (i < n) {
    				// 在可以到达的长度时, 尽可能选择能照更远的
            while (i < n && sections[i].first <= last) {
                tail = max(tail, sections[i].second);
                ++i;
            }
          	// 目前sections[i] 已经超过目前可以到达的长度, 逼不得已买一个眼, 这个眼就是之前`尽可能选择能照更远的`的眼
            ++output;
            last = tail;
          	// 若目前能到达的长度已经超过l, 可以完全覆盖
            if (last > l) {
                cout << output;
                return 0;
            }
          	// 不连续, 不能完全覆盖
            if (sections[i].first > tail) {
                cout << "-1";
                return 0;
            }
        }
      	// 区间用完了, 但若目前能到达的长度也到达不了l
        if (tail < l)
            cout << "-1";
    }



编辑于 2022-03-03 16:15:22 回复(0)

#include<vector>
#include<iostream>
#include<algorithm>

using namespace std;


int main(){
    int n, L;
    cin >> n >> L;
    vector<vector<int>> spans(n,vector<int>(2,0));
    for(int i =0; i < n; i++){
        cin >> spans[i][0] >> spans[i][1];
    }
    sort(spans.begin(), spans.end());
    int ans = 0;
    // 贪心算法
    int l = 0, r = 0;
    int left = 0, right = n - 1;
    // bool ok = false;
    while(left <= right){
        int i = left;
        while(i <= right && spans[i][0] <= l && r < L){
            r = max(r, spans[i][1]);
            i ++;
        }
        l = r;
        if(r >= L){
            cout << ans + 1<< endl;
            return 0;
        }
        if(left == i){
           cout << -1 << endl;
           return 0;
        }
        ans ++;
        left = i;
    }
    cout << -1 << endl;
    return 0;
 
}

发表于 2022-01-10 19:30:10 回复(0)
package main

import (
    "fmt"
    "sort"
    "bufio"
    "strings"
    "strconv"
    "os"
)

type pair struct{
    a,b int
}
func main(){
    var n,l int
    fmt.Scan(&n,&l)
    inp:=bufio.NewReader(os.Stdin)
    li:=make([]pair,n)
    for i:=0;i<n;i++{
        str,_:=inp.ReadString('\n')
        str_l:=strings.Split(str[:len(str)-1]," ")
        li[i].a,_=strconv.Atoi(str_l[0])
        li[i].b,_=strconv.Atoi(str_l[1])
    }
    sort.Slice(li,func(i,j int)bool{
        if li[i].a!=li[j].a{
            return li[i].a<li[j].a
        }else{
            return li[i].b>li[j].b
        }
    })
    r:=0
    con:=0
    id:=0
    for r<l{
        if li[id].a>r{
            fmt.Println(-1)
            return
        }
        p:=0
        for ;id<n&&li[id].a<=r;id++{
            p=max(p,li[id].b)
        }
        r=p
        con++
        if r>=l{
            fmt.Println(con)
            return 
        }
        if id>=n{
            fmt.Println(-1)
            return
        }
    }
}
func max(a,b int)int{
    if a>b{
        return a 
    }
    return b
}

发表于 2022-01-06 19:43:44 回复(0)
        这是电竞学院 LOL 分部考试题吗?
        比较简单的贪心法,使用了优先级队列作为辅助,代码如下:
// 贪心法即可解决这个问题
#include<iostream>
#include<queue>
 
using namespace std;
 
int main() {
    int n, L, l, r, res = 0, max_step = 0;
    cin >> n >> L;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pQue;;
    for(int i = 0; i < n; ++i) {
        cin >> l >> r;
        pQue.push({l, r});
    }
    while(max_step < L && !pQue.empty()) {
        int tmp = max_step;
        while(!pQue.empty() && pQue.top().first <= max_step) {
            tmp = max(tmp, pQue.top().second);
            pQue.pop();
        }
        if(tmp <= max_step)
            break;
        else {
            max_step = tmp;
            res += 1;
        }
    }
    if(max_step >= L)
        cout << res << endl;
    else
        cout << -1 << endl;
    return 0;
     
}


发表于 2021-09-07 14:45:19 回复(0)
n, L = [int(x) for x in input().split()]
nums = []
while(n>0):
    n -= 1
    tmp = [int(x) for  x in input().split()]
    nums.append(tmp)

nums.sort(key=lambda x: (x[0], -1*x[1]))
pre_end = nums[0][1]
ans = [nums[0]]
cover_max = 0
i = 1
while i < len(nums):
    start, end = nums[i][0], nums[i][1]
    if start <= pre_end:
        cover_tmp = end - pre_end
        if cover_max < cover_tmp:
            i_select = i
            cover_max = cover_tmp
        i += 1
    else:
        ans.append(nums[i_select])
        pre_end = nums[i_select][1]
        cover_max = 0
        if pre_end >= L:
            break
if pre_end < L:
    ans.append(nums[i_select])

if ans[-1][1]>= L:
    print(len(ans))
else:
    print(-1)

发表于 2021-08-02 09:44:07 回复(0)
贪心算法,每次都选择可以覆盖到最远距离的地方
importjava.util.*;
publicclassMain{
    publicstaticvoidmain(String[] args){
        Scanner sc = newScanner(System.in);
        intn = sc.nextInt();
        intl = sc.nextInt();
        int[][] a = newint[n][2];
        for(inti=0;i<n;i++){
            a[i][0] = sc.nextInt();
            a[i][1] = sc.nextInt();
        }
        Arrays.sort(a,newComparator<int[]>(){
            publicintcompare(int[] arr1,int[] arr2){
                if(arr1[0]!=arr2[0]){
                    returnarr1[0]-arr2[0];
                }else{
                    returnarr1[1]-arr2[1];
                }
            }
        });
        intstart = 0;
        intleft = 0;
        intnum = 0;
        while(left<a.length && start<l){
            if(a[left][0]>start){
                System.out.println(-1);
                break;
            }
            intmax = a[left][1];
            intmaxIndex = left;
            while(left<a.length && a[left][0]<=start){
                if(a[left][1]>=max){
                    max = a[left][1];
                    maxIndex = left;
                }
                left++;
            }
            num++;
            start = a[maxIndex][1];
        }
        if(start>=l){
            System.out.println(num);
        }else{
            System.out.println(-1);
        }
         
    }
}
发表于 2021-07-29 22:57:11 回复(0)
就能过60%, 求大佬解答一下啊
#include<iostream>
#include<vector>
#include<cstdlib>
#include <algorithm>
using namespace std;
int main(void){
    int n,l,i,x,y,end,tmp,count,find,tend;
    cin>>n>>l;
    vector<vector<int>>shiye(n);
    for(i=0;i<n;i++){
        cin>>x>>y;
        shiye[i]={x,y};
    }
    sort(shiye.begin(),shiye.end(),[](vector<int>&a,vector<int>&b){return a[0]<b[0]||(a[0]==b[0]&&a[1]>b[1]);});
    end=shiye[0][1];
    if(shiye[0][0]==0){
        count=1;
    }
    else{
        cout<<-1<<endl;
        goto a;
    }
    tmp=0;
    while(end<l){
        find=0;
        tend=end;
        for(i=tmp+1;i<n&&shiye[i][0]<tend;i++){
            if(end<shiye[i][1]){
                find=1;
                tmp=i;
                end=shiye[i][1];
            }
        }
        if(find==0){
            cout<<-1<<endl;
            goto a;
        }
        else
            count++;
    }
    cout<<count<<endl;
    a: return 0;
}
发表于 2021-04-24 11:22:59 回复(0)
90%,找不出问题
import java.util.Scanner;
import java.util.Arrays;
 
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int size = sc.nextInt();
        int length = sc.nextInt();
        int[][] guard = new int[size][2];
        for(int i = 0;i < size;i++) {
            for(int j = 0;j < 2;j++) {
                guard[i][j] = sc.nextInt();
            }
        }
        System.out.println(solute(guard,length));
    }
    public static int solute(int[][] guard,int length) {
             Arrays.sort(guard, (a, b) -> {
            if(a[0] == b[0]){
                return b[1] - a[1];
            }else {
                return a[0] - b[0];
            }
        });
        
        int right = guard[0][1];
        int count = 1;
        for(int i = 0;i < guard.length;i++) {
            i--;
            if(right >= length) return count;
            int max = Integer.MIN_VALUE;
            while (i + 1 < guard.length && guard[i + 1][0] <= right) {
                i++;
                if(guard[i][1] > max) {
                    max = guard[i][1];
                }
            }
            if(max == Integer.MIN_VALUE) {
                return -1;
            }
            right = max;
            count++;
        }
        return count;
    }
}


发表于 2021-04-17 16:55:18 回复(0)
这题我按左闭右开的做才全过的,题目说的明明是左闭右闭,题目有问题
发表于 2021-03-20 13:31:59 回复(0)