题目:
有个叫做“嘻哈华”的同学,他所在的学校将举办一次活动,现在他想知道一个教室最多能安排的活动数?现在告诉他活动开始时间与结束时间,问:最多活动数?
思路:
这个时间可以是数字,也可以是字符串形式如“11:25”或者“03:21”,注意到我们可以用sort对字符串进行排序,只要他们是长度相同的,尽管中间有:但是都有那就相同不会影响的!!!所以遇到这种输入不要慌!直接排序
这个题目的思路就是贪心原则,自定义排序规则对时间的结尾进行排序,结尾越靠近前面就排序到前面,就是对结尾从小到大排序。贯彻贪心原则,这个是符合贪心的。如果有最靠前的结尾,为什么不选! 不然选择靠后的结尾,在后面选择的时候就少了很多时间了!
方便理解就是,我总要参加活动,每个活动都有结束时间,我为了最大化安排,肯定先看哪个活动先结束。然后再看后面的活动开始时间是不是大于结束时间,如果是就参加。不是就看后面的
#include<bits/stdc++.h>
using namespace std;
bool cmp(vector<string>x,vector<string>y){
return x[1]<y[1];
}
int main(){
string s1;
vector<vector<string>> temp(3,vector<string>(2));
for(int i=0;i<3;i++){
string t;
vector<string>tt;
getline(cin,s1);
stringstream ss(s1);
while(getline(ss,t,' '))
tt.push_back(t); //二维的话增加一个辅助,不能用temp[i]
temp[i]=tt;
}
/完成输入
int ans=1;
sort(temp.begin(),temp.end(),cmp);
string end=temp[0][1];
for(int i=1;i<temp.size();i++){
if(temp[i][0]>=end){
ans++;
end=temp[i][1];
}
}
cout<<ans;
}
或者 ,也就是说push_back是在没分配的空间内增加,你提前给他增加了2,默认是0的,你push在外围了!!!
#include<bits/stdc++.h>
using namespace std;
bool cmp(vector<string>x,vector<string>y){
return x[1]<y[1];
}
int main(){
string s1;
vector<vector<string>> temp(3);
for(int i=0;i<3;i++){
string t;
vector<string>tt;
getline(cin,s1);
stringstream ss(s1);
while(getline(ss,t,' '))
temp[i].push_back(t);
//cout<<temp[0][0];
}
/完成输入
int ans=1;
sort(temp.begin(),temp.end(),cmp);
string end=temp[0][1];
for(int i=1;i<temp.size();i++){
if(temp[i][0]>=end){
ans++;
end=temp[i][1];
}
}
cout<<ans;
}
——————————————————————————————————————————————————————变体:
1353. 最多可以参加的会议数目
思路:
注意到,这个题目和上面的题目不同在于,上面的题目不允许重合,而这个题目允许重合,比如1,4天内选择一天,2,3天内选择一天,他们重合了,但是都可以参加。这样贪心算法就不能从尾巴入手了
这个题目可以通过这样的手段来解决。我们首先用一个哈希表建立开始时间和结束时间的映射,就是某个开始时间肯定有若干个结束时间,注意到这里的若干个,对应了若干个会议了!!!! 也就是说我们找出同一个时间开始的会议 ,很明显哪个会议先结束,我们就去参加哪个会议,这是属于这个时间内去参加会议的最大收益了!!
遍历时间点,看这个时间点是否有会议开展,如果有,进入最小队列
因为之前也有会议进入我们的最小队列,只是结束时间太迟了,没参加,如果到今天发现已经有会议结束了,那就要出栈
然后看下队列中结束时间最小的会议,咱们去参加结束时间最短的会议!!!然后会议次数+1;
我也用了类似的解决方式,首先把当前day能够参加的会议全部丢进一个结束时间的小根堆中,这样最顶上的会议就会是先结束的,先结束的肯定是要先做的,这是贪心策略,因为后结束的在之后还有机会做。因为每天只能参加一个会议,所以从结束栈顶弹出一个参加,重复这些操作最后等所有会议都过期或者参加了就结束了。这个策略为什么可行,比如第一天1,1或者1 4 如果第四天结束我可以缓缓,如果第一天结束,那我为什么不参加;但是比如第一天参加的会议1:4天都行 出栈呗,反正今天能!!!!注意到一旦count了,表示今天肯定肯定是可以参加会议的,看下今天如果是2 2不用多说,如果是2 1,这个1比2要小,过期了就不参加了;比如2 4 2 3,在队列,那我就出这个3,其实这个出就是说把这个会议给他解决了,后面的数字只是轻重缓急!!!别被迷惑了,因为3,剩下的4你可以明天参加啊或者后天
class Solution {
public:
int maxEvents(vector<vector<int>>& events) {
int maxDay = 0;
// 构建一个【开始天】 和 【结束天】的映射
unordered_map<int, vector<int>> day2days;
for (vector<int>& event : events)
{
if (maxDay < event[1])
{
maxDay = event[1]; //最多有这么多天
}
day2days[event[0]].push_back(event[1]);
}
// 记录参见会议的次数
int res = 0;
// 小顶堆队列
priority_queue<int, vector<int>, greater<int>> q;
for (int i = 1; i <= maxDay; ++i) //看看这么多天那一天参加会议
{
// 增加新的结束时间
if (day2days.count(i)) //如果找到i
{
for (int day : day2days[i]) //结束天入队列
q.push(day);
}
// 删除队列里结束时间小于i的会议:因为它们已经结束了,无法再选择
while (!q.empty() && q.top() < i)
{
q.pop();
}
// 直接取最小结束时间会议,次数+1
if (!q.empty())
{
q.pop();
++res;
}
}
return res;
}
};