http://acm.hdu.edu.cn/showproblem.php?pid=5360
PS: 主要到这道题是special judge 答案不唯一
题目大意:邀请n个人去旅游,给出每个人同意邀请时对人数的限制条件:最小人数和最大人数,一旦接收邀请就不会再退出,求一个序列,在这个序列中可以邀请到最多的人去旅游。
//5360 贪心 //范围在l~r //输出最大的soda的数量,在第二行输出n个数的排列 //http://blog.csdn.net/cq_pf/article/details/47320545 //n个人接受邀请的条件是已经接受邀请的人数区间在l[i] , r[i] //问怎样设置邀请顺序能使得接受邀请的人数最多 //先对其对从小到大排序 //然后维护一个set,set中存入左边满足条件的所有人, //然后贪心策略是每次取左边满足条件的右边最小的人 //每次多邀请一个人后删除右边不满足条件的人 #include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <string> #include <set> using namespace std; //set与multiset讲解 //http://blog.csdn.net/xiajun07061225/article/details/7459206 multiset讲解 //http://blog.csdn.net/cq_pf/article/details/47320545 本题 const int maxn = 1e5 + 5; struct node { int l, r, id; bool operator<(const struct node tmp) const { if (l == tmp.l) return r < tmp.r; else return l < tmp.l; } }p[maxn]; multiset<pair<int, int >>s; multiset<pair<int, int >>::iterator it; int vis[maxn];//被选上了标记为1 int a[maxn];//最终答案 int main() { //freopen("in.txt","r",stdin); int t; int n; scanf("%d", &t); while (t--) { memset(vis, 0, sizeof(vis));//选上的要标记,因为后面要把没选上的输出 scanf("%d", &n); for (int i = 1; i <=n; i++) { scanf("%d", &p[i].l); p[i].id = i; } for (int i = 1; i <= n; i++) { scanf("%d", &p[i].r); } sort(p + 1, p + 1 + n); int ans = 0;//当前已经选出的人数 int i = 1; s.clear(); while (1) { while (ans >= p[i].l && i <= n) { s.insert(make_pair(p[i].r, p[i].id)); i++; } if (!s.size()) //当s已经清空完了,弹出大的while break; while (s.size()) { it = s.begin(); if (it->first >= ans) break; s.erase(s.begin());//不符合的都弹出去 } if (s.size()) //把剩下符合的放在a[]中 { it = s.begin(); a[++ans] = it->second; vis[it->second] = 1; s.erase(s.begin()); } } printf("%d\n", ans); for (int i = 1; i <= n; i++) //补满输出的数组 { if (!vis[i]) a[++ans] = i; else vis[i] = 0; } for (int i = 1; i <= ans; i++) printf(i == ans ? "%d\n" : "%d ", a[i]); } //fclose("out.txt", "r", stdout); system("pause"); return 0; }
优先队列做法:
首先对n个人的最小人数限制由小到大排序,记录当前已经接受邀请的人数,然后将满足最小人数的人加入优先队列,优先队列按照最大人数由小到大排列,每次吐出的都是最大人数限制的最小值,如果当前的人数小于等于最大的人数就可以邀请到,否则就邀请不到。每当接受邀请的人数增加,就循环一次,直到所有人都遍历完。
// hdu 5360 优先队列 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <queue> #include <vector> using namespace std; //http://www.bubuko.com/infodetail-1029311.html 优先队列 const int maxn = 1e5 + 5; struct node { int l, r; int id; bool operator<(node a)const { return a.r < r;//按照最大值排列 } }p[maxn],q; priority_queue <node> que; int vis[maxn]; vector<int>vec; int cmp(node n1, node n2) //先把结构体按照最小值的顺序排列 { return n1.l < n2.l; } int main() { //freopen("in.txt", "r", stdin); int t, n; int num; scanf("%d", &t); while (t--) { //把优先队列,标记数组,向量 重置为初始状态 //一般有这种 t-- 要输入很多组数据的都有这一步。。。。。。。 while (!que.empty()) que.pop(); memset(vis, 0, sizeof(vis)); vec.clear(); scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &p[i].l); p[i].id = i + 1; } for (int i = 0; i < n; i++) { scanf("%d", &p[i].r); } sort(p, p + n, cmp); num = 0; int i = 0; for (int j = 0; j < n; j++) { while (i < n) //满足最小人数的先放入优先队列 { if (p[i].l <= num) { que.push(p[i]); i++; } else break; } while (!que.empty()) //如果优先队列里的数每个的最大值符合,就把id放到向量里面 { if (que.top().r >= num) { vec.push_back(que.top().id); vis[que.top().id] = 1; que.pop(); num++; break; } else que.pop(); } } //输出了 int cnt = 0; printf("%d\n", vec.size()); for (int i = 0; i < vec.size(); i++) { cnt++; printf(cnt == n ? "%d\n" : "%d ", vec[i]); } for (int i = 1; i <= n; i++) { if (!vis[i]) { cnt++; printf(cnt == n ? "%d\n" : "%d ", i); } } } system("pause"); //freopen("out.txt", "r", stdout); return 0; }