#include<iostream> #include<vector> #include<algorithm> using namespace std; int main(){ int n; cin>>n; vector<pair<int,int>> record; for(int i=0;i<n;i++){ int a,b; cin>>a>>b; record.push_back(make_pair(a,b)); } sort(record.begin(),record.end()); int count = 2; //l和r表示选点区间 int l = record[0].first; int r = record[0].second; for(int i=1;i<record.size();i++){ if(record[i].first>=l&&record[i].first<=r){ l = record[i].first; r = min(r,record[i].second); }else{ count += 2; l = record[i].first; r = record[i].second; } } cout<<count<<endl; return 0; }
题意:选择一些点,保证每个区间至少包含这些点中的两个。
目标:让这些选点的数量尽可能的少。
主要思路:区间右端排序 + 贪心
百度搜《区间选点》,有一大堆写的很好的博客,看了就懂了。
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[][] arr = new int[n][2]; for(int i = 0; i < n; i ++) { arr[i][0] = sc.nextInt(); arr[i][1] = sc.nextInt(); } Arrays.sort(arr, (e1, e2) -> e1[1] - e2[1]); LinkedList<Integer> list = new LinkedList<>(); list.add(arr[0][1] - 1); list.add(arr[0][1]); for(int i = 1; i < n; i ++) { if(arr[i][0] > list.peekLast()) { // 相离 list.add(arr[i][1] - 1); list.add(arr[i][1]); } else if(arr[i][0] > list.get(list.size() - 2)) { list.add(arr[i][1]); } } System.out.println(list.size()); } }
#贪心,按右端排序后,遍历区间,如果遍历到的区间代表数不够,每次优先取最右两个数 def slove(a): a.sort() set1=set() for l in a: s=l[-1] e=l[0] cn=0 for i in range(s,e+1): if i in set1: cn+=1 if cn==2: break if cn==0: set1.add(e-1) set1.add(e) if cn==1: set1.add(e) return len(set1) if __name__=="__main__": n=int(input().strip()) a=[] for i in range(n): l=list(map(int,input().strip().split())) a.append(l[::-1]) if n==0: print(0) else: print(slove(a))
// 右端排序 贪心 #include<bits/stdc++.h> using namespace std; struct P { int s, e; }; int main() { int n = 0; cin >> n; P *p = new P[n]; for (int i=0; i<n; ++i) { cin >> i[p].s >> i[p].e; } sort(p, p+n, [](P& a, P& b) { return a.e < b.e; } ); int ans = 2; int l = 0[p].s; int r = 0[p].e; for (int i=1; i<n; ++i) { if (r >= i[p].s) { if (r - i[p].s + 1 < 2) { ++ans; r = i[p].e; } } else { ans += 2; l = i[p].s; r = i[p].e; } } cout << ans << endl; delete p; return 0; }
#include <bits/stdc++.h> using namespace std; struct P{ int a, b; P(){} P(int a, int b):a(a),b(b){} }; bool cmp(P p1, P p2){ return p1.b < p2.b; } int main(){ int n; cin>>n; P p[n]; for(int i=0;i<n;i++){ int x,y; cin>>x>>y; p[i] = P(x,y); } sort(p,p+n,cmp); int cnt = 0, l=-1, r=-1; for(int i=0;i<n;i++){ if(p[i].a > l){ cnt++; l = r; r = p[i].b; } if(p[i].a > l){ cnt++; l = p[i].b-1; } } cout<<cnt<<endl; return 0; }
/* 贪心算法,参考课程安排 按右端排序,若挑选的数不在区间内,尽可能取右端 每次更新p1计数 */ #include<bits/stdc++.h> using namespace std; #define N 10000 struct area { int a, b; }; bool cmp(pair<int, int> x, pair<int, int> y) { return x.second < y.second; } int main() { // freopen("input.txt", "r", stdin); int n, i; cin >> n; vector<pair<int, int> > a(n); for(i = 0; i < n; i++) { cin >> a[i].first >> a[i].second; } sort(a.begin(), a.end(), cmp); int p1 = -1, p2 = -1, ans = 0; for(i = 0; i < n; i++) { if(a[i].first > p1) { ans++; p1 = p2; p2 = a[i].second; } if(a[i].first > p1) { ans++; p1 = a[i].second - 1; } } cout << ans << endl; return 0; }
N, l = int(input()), [] a = [tuple(map(int, input().split())) for i in range(N)] b = [a[i][1] for i in range(N)] while b: m = min(b) i = b.index(m) if not l or a[i][0] > l[-1]: l += [m - 1, m] elif l[-2] < a[i][0] <= l[-1]: l.append(m) b.pop(i) a.pop(i) print(len(l))
private static class Line{ int left,right; public Line(int left,int right){ this.left=left; this.right=right; } } public static void main (String[] args) throws IOException { BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); int n=Integer.parseInt(bf.readLine()); Line[]lines=new Line[n]; for (int i = 0; i < n; i++) { String[]s=bf.readLine().split(" "); lines[i]=new Line(Integer.parseInt(s[0]),Integer.parseInt(s[1])); } int cnt=2; Arrays.sort(lines,0,n,new cmp()); int l1=lines[0].right; int l2=lines[0].right-1; for (int i = 1; i < n ; i++) { if (l1<lines[i].left){ cnt+=2; l1=lines[i].right; } else if (l1==lines[i].left){ cnt+=1; l1=lines[i].right; }else{ continue; } } System.out.println(cnt); } private static class cmp implements Comparator<Line> { @Override public int compare(Line o,Line k) { int t=o.right-k.right; if (t==0){ t=k.left-o.left ; } return t; } }
n=int(input()) import sys data=[] for i in range(n): data.append(list(map(int,sys.stdin.readline().strip().split()))) #区间找点问题,按右端排序 data=sorted(data,key=lambda x:x[1]) res=set() for i in data: count=0 for k in range(i[0],i[1]+1): if k in res: count+=1 if count==2: break if count==0: res.add(i[-1]-1) res.add(i[-1]) if count==1: res.add(i[-1]) print(len(res))
这种办法还可以做每个区间取不同点的情况,只需要把intervals类的constructor加一个对pointNumber的初始化操作
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
intervals[] intervals = new intervals[n];
for (int i = 0;i < n;i++)
intervals[i] = new intervals(scanner.nextInt(),scanner.nextInt());
Arrays.sort(intervals);
int max = intervals[n - 1].right;
int[] axis = new int[max + 1];
for (int i = 0;i < n;i++){
int left = intervals[i].left;
int right = intervals[i].right;
int sum = sum(axis,left,right);
int gap = intervals[i].pointNumber - sum;
while (gap > 0){
if (axis[right] == 0) {
axis[right--] = 1;
gap--;
}
else right--;
}
}
System.out.println(sum(axis,0,max));
}
}
public static int sum(int[] axis,int left,int right){
int sum = 0;
for (int i = left;i <= right;i++)
sum += axis[i];
return sum;
}
public static class intervals implements Comparable<intervals>{
public int left;
public int right;
public int pointNumber = 2;
public intervals(int left,int right){
this.left = left;
this.right = right;
}
@Override
public int compareTo(intervals other) {
int temp = this.right - other.right;
return temp != 0 ? temp : this.left - other.left;
}
}
}
#include<iostream> #include<vector> #include<set> #include<algorithm> using namespace std; int main(){ int n,beg,end,res=0,t; cin>>n; vector<pair<int,int>> itval; set<int> sel; for(int i=0;i<n;i++){ cin>>beg>>end; itval.push_back(make_pair(end,beg)); } sort(itval.begin(),itval.end()); sel.insert(itval[0].first); sel.insert(itval[0].first-1); set<int>::iterator iter; for(int i=1;i<n;i++){ iter=sel.lower_bound(itval[i].second); t=2; while(t>0&&iter!=sel.end()&&*iter>=itval[i].second&&*iter<=itval[i].first){ t--; iter++; } if(t==2){ sel.insert(itval[i].first); sel.insert(itval[i].first-1); }else if(t==1){ sel.insert(itval[i].first); }else ; } cout<<sel.size()<<endl; return 0; }没有看出来这个和课程安排思路是一致的😂,按右端点排序,然后添加区间最右边两个点,新区间添加时检查区间内已经有几个点了,然后再决定是否再加点。
//#include "utils.cpp" #include <bits/stdc++.h> using namespace std; //freopen("temp.in","r",stdin); #include <bits/stdc++.h> using namespace std; /* 贪婪法 区间按最右端 从小到大排序 p1,p2表示前一区间选择的点(开始时是第一个区间最右边两点) 判定现在的区间是否包含 包含则跳过 不包含时 用新区间最右边两点替换 只包含右边一点时,p1=p2,p2=新区间最右边点 */ struct T{ int a; int b; T(){} T(int a_,int b_):a(a_),b(b_){} //按区间最右端 从小到大排序 bool operator<(const T &t){ if(b==t.b) return a<t.b; return b<t.b; } }; int main(){ //freopen("temp.in","r",stdin); int N; cin>>N; int a,b; vector<T> A(N); for(int i=0;i<N;i++){ cin>>a>>b; A[i]=T(a,b); } sort(A.begin(),A.end()); bool token = false;//与前面区间的重合长度是否为1 int ans = 2; int p1,p2;//选中的两个点 p1 = A[0].b-1,p2 = A[0].b; for(int i=1;i<N;i++){ //新区间与选中的点无交集 更新两点 if(A[i].a>p2){ ans+=2; p1=A[i].b-1; p2=A[i].b; continue; } //完全包含两点 if(A[i].a<=p1 and A[i].b>=p2) continue; //仅包含右边点 因为区间是按右端升序的 if(A[i].a>p1 and A[i].a<=p2){ ans+=1; p1 = p2; p2 = A[i].b; }; } cout<<ans<<endl; return 0; }
import java.util.*; public class Main { public static class seg { public int a; public int b; public seg(int a, int b) { this.a = a; this.b = b; } } public static class segSort implements Comparator<seg> { public int compare(seg i1, seg i2) { return i1.b != i2.b ? i1.b - i2.b : i2.a - i1.a; } } public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); seg[] s = new seg[n]; for(int i = 0; i < n; i ++) { int a = in.nextInt(); int b = in.nextInt(); s[i] = new seg(a, b); } Arrays.sort(s, new segSort()); int p1 = s[0].b - 1; int p2 = s[0].b; int count = 2; for(int i = 1; i < n; i ++) { if(s[i].a <= p1 && s[i].b >= p2) continue; else if(s[i].a <= p2) { count += 1; p1 = s[i].b - 1; p2 = s[i].b; } else if(s[i].a > p2) { count += 2; p1 = s[i].b - 1; p2 = s[i].b; } } System.out.println(count); } }
#include<bits/stdc++.h> using namespace std; int main(){ int n; cin >> n; map<int,int> m; int a,b; for(int i=0;i<n;i++){ cin >> a >> b; m.insert({b,a}); //按右区间排序 } map<int,int>::iterator p; p=m.begin(); int a1 = p->first -1; //把第一个区间先取两个值,右区间-1 和 右区间 int b1 = p->first; //cout << a1 << " " << b1 << endl; int num=2; for(int i=1;i<n;i++){ p++; if(a1 >= p->second && b1 <= p->first) continue; //包含该两个点,无需再取值 if(b1 < p->second){ //区间该两点都不包含 num = num+2; a1 = p->first -1; b1 = p->first; //cout << "2222" << endl; //cout << "p:" << p->second << " "<< p->first << endl; //cout << a1 << " " << b1 << endl; } if(a1 < p->second && b1 <= p->first){ //区间包含一个点 肯定是前一个点 a1 。。。所以重新取 b1 即可 cout << "p:" << p->second << " " << p->first << endl; num++; a1 = b1; b1 = p->first; //cout << "1111" << endl; //cout << a1 << " " << b1 << endl; } } cout << num << endl; return 0; }
import java.util.Arrays; import java.util.Comparator; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[][] nums = new int[n][2]; for (int i = 0; i < n; i++) { nums[i][0] = sc.nextInt(); nums[i][1] = sc.nextInt(); } Arrays.sort(nums, Comparator.comparingInt(o -> o[1])); int cnt = 1, end = nums[0][1]; for (int i = 1; i < n; i++) { if (nums[i][0] <= end) { continue; } cnt++; end = nums[i][1]; } System.out.println(cnt * 2); } }
import java.util.Arrays; import java.util.Scanner; //52 /*右端点排序,按条件判断(倾向于选最右边的)*/ public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[][] a = new int[n][2]; for (int i = 0; i < n; i++) { a[i][0] = sc.nextInt(); a[i][1] = sc.nextInt(); } Arrays.sort(a, (a1, a2) -> a1[1] - a2[1]); // 右端点排序 int res = 2;// 至少需要两个 int temp = a[0][1]; for (int i = 1; i < n; i++) { if (a[i][0] > temp) { res += 2; temp = a[i][1]; } else if (a[i][0] == temp) { res += 1; temp = a[i][1]; } } System.out.println(res); } }
import java.util.*; public class Main { public static void main(String[] args) { // 1、输入 Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int[][] arr = new int[N][2]; for(int i = 0; i < N; i++) { arr[i][0] = sc.nextInt(); arr[i][1] = sc.nextInt(); } // 2、排序(按照区间右端排序) Arrays.sort(arr, new Comparator<int[]>() { public int compare(int[] a, int[] b) { return a[1] - b[1]; } }); if(N == 1) { System.out.println(2); return; } if(N < 1) { System.out.println(0); return; } // 3、贪心 LinkedList<Integer> list = new LinkedList<>(); list.add(arr[0][1]-1); list.add(arr[0][1]); for(int i = 1; i < N; i++) { if(arr[i][0] > list.getLast()) { list.add(arr[i][1]-1); list.add(arr[i][1]); }else if(arr[i][0] > list.get(list.size()-2)) { list.add(arr[i][1]); } } System.out.println(list.size()); } }
def min_num(nums): nums.sort(key=lambda x:x[1]) count = 0 pre_sec = [-float('inf'), -float('inf')] for left, right in nums: if left > pre_sec[1]: count += 2 pre_sec = [right-1, right] elif pre_sec[0] < left and left <= pre_sec[1]: count += 1 pre_sec = [pre_sec[1], right] return count n = int(input()) nums = [] for i in range(n): nums.append([int(x) for x in input().split()]) print(min_num(nums))
def func(n, sections): sections.sort() bi = sections[0][0] select_nums = [bi - 1, bi] for section in sections: ai = section[1] bi = section[0] if ai <= select_nums[-2]: continue elif ai <= select_nums[-1]: select_nums.append(bi) else: select_nums.append(bi) select_nums.append(bi - 1) print(len(select_nums)) n = int(input()) sections = [] for i in range(n): ai, bi = map(int, input().split()) per_section = (bi, ai) sections.append(per_section) func(n, sections)