Uva 1617 有时候题目可能没有你想得那么复杂...
一、题意
给你n条线段(线段端点为整数,n<=100000),输入保证线段间没有包含关系,且保证有解。
现在要求将每条线段截取长度为1的一小段,使得截取后的所有线段之间的空隙数目最少。
输出空隙的最少数目。
二、解析
一开始用了一种比较复杂的方法:
将所有线段按右端点排序后,每个线段尽量靠左边选取长度为1的片段,并维护一个remain值,表示该长度为1的片段右侧的空余长度(也就是可以动态右移多少长度);还要维护一个cur值,表示当前已经选取的1片段的最右端位置。然后每次当发现当前线段与上一线段的1片段(cur值)之间有空隙时,首先检查remain能否填充这个空隙,若能,则将该空隙填充;若不能则说明这个空隙必须存在,即ans++。每次判定完一个片段需要更新remain值、cur值。
这算是一种比较完备的思路,具体见后面代码。后来在网上发现一种简单一些的思路:
由于题目中已经保证有解,因此其实根本不需要判定是否放得下,只需要执行贪心策略即可:即还是按照线段的右端点排序,然后第一个线段选取最靠右边的长度为1的片段(贪心),然后后续线段就紧靠着选取即可。若发现无法紧靠,即必然有空隙,则ans++;否则就一定能放得下。这种方法就只需要维护一个cur值表示当先选取的1片段得最右端即可。
唯一要细节处理得就是,若当前线段与已选取1片段得最右端重合,则不需要改变cur值,因为题目保证有解,所以这里隐含得操作实际上是,将前面的所有片段左移1个单位,然后再将当前1片段放在这里。
三、代码
- 比较完备的代码
#include <iostream> #include <algorithm> using namespace std; const int maxn = 1e5 + 5, INF = 1 << 30; struct section{ int l, r; bool operator < (const section& rhs) const { return r < rhs.r || r == rhs.r && l < rhs.l; } } a[maxn]; int kase, n; int main(){ cin >> kase; while(kase --){ cin >> n; for(int i = 0; i < n; i ++) cin >> a[i].l >> a[i].r; sort(a, a + n); int ans = 0, remain = INF, cur = a[0].l; for(int i = 0; i < n; i ++){ if(cur + 1 > a[i].r) ans ++, cur = a[i].l + 1; else if(cur < a[i].l){ if(a[i].l - cur <= remain) remain -= a[i].l - cur; else ans ++, remain = INF; cur = a[i].l + 1; } else cur ++; remain = min(remain, a[i].r - cur); } cout << ans << endl; } }
- 比较取巧的代码
#include <iostream> #include <algorithm> using namespace std; const int maxn = 100000 + 5; struct section { int l, r; bool operator < (const section& rhs) const { return r < rhs.r || r == rhs.r && l < rhs.l; } } a[maxn]; int kase, n; int main() { cin >> kase; while(kase --) { cin >> n; for(int i = 0; i < n; i ++) cin >> a[i].l >> a[i].r; sort(a, a + n); int cur = a[0].r, ans = 0; // 贪心:第一个片段靠最右边放,之后的依次紧靠 for(int i = 1; i < n; i ++) { if(a[i].l > cur) ans ++, cur = a[i].r; else if(a[i].r == cur) continue; else cur ++; // 由于线段端点为整数,所以只要右端不相等,就至少大1,一定足够放 } cout << ans << endl; } }
四、归纳
- 要仔细看清楚题目,说不定题目没有你想的那么复杂....
- 大多数时候,题目的输入全为整数值,这代表“偏移量”等要么为0,要么为1,这可能是简化题意的关键
一起来重刷题叭~ 由于精力有限,题意只说大概,题目细节可以点击vjudge链接查看。 题目以紫薯中的Uva例题/习题为主,有时候有些比较经典的算法也会特意从其它OJ上找题,并不一定出现在紫薯上。 噢,紫薯指——《算法竞赛入门经典(第2版)》by 刘汝佳 喜欢的小伙伴点个赞呗?不然我只能认为一直只有我一个人在自娱自乐orz....