Description
有一些同学在练习匀速跑,他们起点和速度各不相同,但约定好练习相同的时间。
请根据给出的同学的初始位置和速度,计算至少需要多少条跑道才能保证同学之间互相不会相撞。在任何一个时间点两个不同的同学处在相同的位置均视为相撞。
Input Format
第一行:两个整数N和T。N (1 <= N <= 1,000,000) 代表总人数,T (1 <= T <= 1,000,000,000)代表所有人跑步的时间。
第2 ~ (N+1)行:两个整数,第一个代表起始位置,第二个代表速度。
Output Format
一个整数,输出最小跑道数量。
Sample Input:
5 3
0 1
1 2
2 3
3 2
6 1
Sample Output:
3
其实。。这个题的数据是按照起点排序过后的,所以不必再进行排序了。
判断两个人是否会相交,可以根据在直角坐标系中两条线段是否相交的关系来确定检查函数
另外这个题的数据比较大,要用ULL,而且是每一个中间计算结果也要用ULL
具体算法是有点类似于贪心算法
策略就是每条新的道路尝试加入所有还未处理的人,如果都没法加入了,开一个新的道路。
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef unsigned long long ULL; struct Period { ULL start; ULL end; bool done; }; bool cmp_period(const Period& a,const Period& b){ return a.start < b.start; } inline bool check(ULL s,ULL e,const Period& b){ return ((s < b.start) and (e < b.end)); } Period ps[1000000]; int main(int argc, char const *argv[]) { ULL N,T; cin>>N>>T; for (ULL i = 0; i < N; ++i) { scanf("%d",&ps[i].start); ULL v; scanf("%d",&v); ps[i].end = ps[i].start + v*T; ps[i].done = false; } //sort(ps,ps+N,cmp_period); //按照起点排序 ULL ans = 0; for (ULL i = 0; i < N; ++i) if(!ps[i].done) { ans++;//加入一个新跑道 ULL e = ps[i].end; ps[i].done = true; //此处的查找可以优化成二分查找 因为是排序过的 for (ULL j = i+1; j < N; ++j) if(!ps[j].done) { if(check(ps[i].start,e,ps[j])){//判断是否会香蕉 //如果不会相交 e = ps[j].end; //类似区间合并 ps[j].done = true; } } } cout<<ans<<endl; return 0; }
标准程序如下:
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int N, T; cin >> N >> T; vector<long long> A;//存储道路 for (int i = 0; i < N; i++) { long long x, s; cin >> x >> s;//读入起点x和速度s x = -(x + s * T); //设置x为终点的负数 //如果没有一个道路 或者 //如果该人的终点 <= 最后一个道路的终点 就要新建一个道路 //原因是因为最后一个道路的终点肯定是最大的 if (A.empty() || (-A.back()) >= (-x) ) { A.push_back(x);//新建一个道路 用终点的负数来标识道路 } else { //二分查找 找到可以添加的道路 *upper_bound(A.begin(), A.end(), x) = x; //把该人加入之前的某一个道路中 } } cout << A.size() << endl; return 0; }