2 条题解
-
0
看到题解区没有贪心解法,来交一发。蒟蒻第一次做证明,如有勘误,敬请指教。
该题的本质是从 个区间里选择一些区间,在这些区间能覆盖 内所有整数点的前提下,使得选择的区间个数最小。
算法流程:
-
将所有区间按左端点从小到大排序。
-
设 为当前最靠左的没有被覆盖的点。枚举每个区间,在所有能覆盖 的区间中,挑一个右端点最大的作为当前决策。然后更新 。
-
如果找不到能覆盖 的区间,则原问题无解。
利用双指针实现算法。
#include <bits/stdc++.h> using namespace std; struct segment{ int l,r; bool operator<(const segment &x) const{ return l<x.l; } // 重载小于号,用于 sort()。也可以用 cmp() 函数实现同样功能。 }range[25005]; int main(){ int n,ed; scanf("%d%d",&n,&ed); for(int i=1;i<=n;++i) scanf("%d%d",&range[i].l,&range[i].r); sort(range+1,range+n+1); int st=1,ans=0; for(int i=1,j=1;i<=n;){ int r=0; while(j<=n&&range[j].l<=st){ // 左端点要 <= st,即该区间能覆盖 st r=max(r,range[j].r); // 找右端点最大的 j++; } if(r<st) break; // 找不到能覆盖 st 的区间 ans++; if(r>=ed){ // 有解,输出 printf("%d\n",ans); return 0; } st=r+1;i=j; } printf("-1\n"); return 0; }证明:
参考闫学灿《算法基础课》。
只考虑有解的情况。
-
正确性:由于我们每次选择的左端点 上次选择的右端点,所以能保证任意两个区间都是连接的。所以每个整数点都一定会被覆盖到。
-
最优性:假设最优解与该算法得出的解有部分区间选择不同。由于该算法中每次选择右端点最大的区间,所以一定能够覆盖更多的点。如果我们把最优解中选择的区间换成该算法选择的区间,显然答案不会更劣。
综上所述,以上贪心算法能得出最优解。
-
-
0
//Author:XuHt #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 100006, INF = 0x3f3f3f3f; int n, m, f[N], b[N], tot = 0; struct T { int l, r, x; bool operator < (const T w) const { return r < w.r; } } a[N], t[N<<2]; void build(int p, int l, int r) { t[p].l = l; t[p].r = r; t[p].x = l ? INF : 0; if (l == r) return; int mid = (l + r) >> 1; build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r); } void change(int p, int x, int y) { if (t[p].l == t[p].r) { t[p].x = y; return; } int mid = (t[p].l + t[p].r) >> 1; if (x <= mid) change(p << 1, x, y); else change(p << 1 | 1, x, y); t[p].x = min(t[p<<1].x, t[p<<1|1].x); } int ask(int p, int l, int r) { if (t[p].l >= l && t[p].r <= r) return t[p].x; int mid = (t[p].l + t[p].r) >> 1, ans = INF; if (l <= mid) ans = min(ans, ask(p << 1, l, r)); if (r > mid) ans = min(ans, ask(p << 1 | 1, l, r)); return ans; } int main() { cin >> n >> m; b[++tot] = 1; for (int i = 1; i <= n; i++) { scanf("%d %d", &a[i].l, &a[i].r); b[++tot] = a[i].l; b[++tot] = a[i].l + 1; b[++tot] = a[i].r; b[++tot] = a[i].r + 1; } b[++tot] = m; sort(b + 1, b + tot + 1); tot = unique(b + 1, b + tot + 1) - (b + 1); while (b[tot] > m) --tot; sort(a + 1, a + n + 1); build(1, 0, tot); memset(f, 0x3f, sizeof(f)); f[0] = 0; for (int i = 1; i <= n; i++) { a[i].r = lower_bound(b + 1, b + tot + 1, a[i].r) - b; a[i].l = lower_bound(b + 1, b + tot + 1, a[i].l) - b; int num = ask(1, a[i].l - 1, a[i].r - 1) + 1; if (f[a[i].r] > num) { f[a[i].r] = num; change(1, a[i].r, f[a[i].r]); } } if (f[tot] == INF) puts("-1"); else cout << f[tot] << endl; return 0; }
- 1
信息
- ID
- 2180
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 9
- 标签
- 递交数
- 11
- 已通过
- 6
- 上传者