总算遇到个能写的题了。
也忒巧了,这两天刚好在看趣学算法,刚好看到贪心(其实就是第一章Orz),刚好学了个题,刚好就跟这个几乎一样,只不过取等不一样,问题背景不同。
其实把这些订单时间以时间为横轴拼起来,就是一堆可能有重叠的的线段,我们的目的就是找若干条线段,使其不重叠地拼起来,而且线段的数量最多。
这是一个典型的贪心问题。
按照人处理这个问题的直觉,贪心策略可能有三个。引自趣学算法
1.每次从剩余订单中取时间最短的订单来处理。
缺陷:时间最短的订单的起始时间是不知道的,万一最短的刚好是今天最晚的订单,那不就只能处理一个了。
2.每次从剩余订单中取开始时间最早的来处理。
缺陷:开始时间最早的订单的持续时间是不知道的,万一一个订单从早搞到晚,那一天也只能处理一个。
3.每次从剩余订单中取结束时间最早的来处理。
这样的贪心策略是最好的,因为结束时间是由开始时间和持续时间共同决定的,要处理订单时,处理结束时间最早的订单就一定能留下最多的时间。
C++:
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct _order
{
int beg;
int end;
}order;//定义订单结构体,包含开始时间和结束时间
bool modifiedSort(order a,order b)
{
if(a.end==b.end)
return (a.beg>b.beg);
else return (a.end<b.end);
}//自定义排序,优先选择结束早的,如果两者结束时间都一样,那就取开始时间大的(开始得晚的),保证可以支配的时间最多。
//返回a是否比b更优,是则true,否则false
int main(int argc, char const *argv[])
{
int n;cin>>n;
order arr[n];//定义结构体数组
for(int i=0,j;i<n;i++)
cin>>arr[i].beg>>arr[i].end;
//之前读入结构体数组时栽了个跟头,每次读取的是一个结构体的两个数据
//i遍历的是结构体数组,不需要再用另一个变量来遍历什么了
sort(arr,arr+n,modifiedSort);//调用C++自带的快排来排序,排序依据是自定义的排序
//现在结构体数组arr已经被排序过了,和原来已经不一样了,现在按0,1,2...,结束时间是逐渐增加的。
int cnt=1,last=arr[0].end;//last标记最后完成的订单的结束时间,cnt标记订单完成个数
for(int i=1;i<n;i++)
if(arr[i].beg>last)//如果下一个订单的开始时间比上一个的结束时间迟(不可重叠),就可以做
{
cnt++;
last=arr[i].end;
}
cout<<cnt<<endl;
return 0;
}
还提供一组
过不了的
C语言版本
其实不是代码的问题,我不会写快速排序(O(nlogn)),只能用冒泡排序O(n^2)代替,最后TLE。
所以尽量看C++的版本,其实C++和C语法也差不了太多。
#include <stdio.h>
typedef struct _order
{
int beg;
int end;
}order;
int modifiedSort(order a,order b)
{
if(a.end==b.end)
return (a.beg>b.beg);
else return (a.end<b.end);
}
int main(int argc, char const *argv[])
{
int i,j,cnt,last,n,tmp;
scanf("%d",&n);
order arr[n];
int aux[n];//辅助数组,用于嵌套排序
for(i=0;i<n;i++) aux[i]=i;
for(i=0;i<n;i++)
scanf("%d%d",&arr[i].beg,&arr[i].end);
for(i=1;i<n;i++)
for(j=0;j<n-i;j++)
if(!modifiedSort(arr[aux[j]],arr[aux[j+1]]))
{
tmp=aux[j];
aux[j]=aux[j+1];
aux[j+1]=tmp;
}
cnt=1;
last=arr[aux[0]].end;
for(i=1;i<n;i++)
if(arr[aux[i]].beg>last)
{
cnt++;
last=arr[aux[i]].end;
}
printf("%d",cnt);
return 0;
}