Wooden Sticks
题目地址:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19567
大概题意:
一个东西有两个属性值l和r,现在有一堆东西要使用他,分成几小堆使用,每小堆第一个使用需要1点消耗,但要求该小堆的后面使用的每一个东西的两个属性ll和rr都要比小于等于前一个(也就是ll<=l&&rr<=r),问你最少要花费多少点才能把所有东西都用完
这里用的是贪心,刚开始我很不理解这个正确性,后面想着想着就相同了(参考了这个人博客的样例http://blog.csdn.net/lishuhuakai/article/details/8117251)
上面所说的其实就是偏序关系,现在考虑一下贪心的正确性
定义A >= B为A.l>=B.l&&A.r>=B.r
如果这堆东西可以排成A>=B>=C...的顺序,那么答案很简单就是1,问题是会出现ABC..互相没有大小关系,通俗的说就是ABC不能互相包含的时候,那么三者肯定都各自需要一点消耗,那么以A为例,假如序列还存在a,b,c等被A包含着,那么a,b,c的关系又可能如ABC一样,那么关键问题来了A的下一个应该选谁?其实选谁都一样,因为这个点(例)a现在不选的,那么以后肯定要选a(BC顺便选a那是最好的情况,BC也遇到A的情形的话...循环想下去,最后肯定存在一个d点只能某D点选或者没有人选,没人选的话则必须花费一点消耗),...最后效果都一样
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <queue> #include <cstdlib> #include <algorithm> #include <stack> #include <map> #include <queue> #include <vector> using namespace std; const int maxn = 1e4+100; const int INF = 0x3f3f3f3f; #define pr(x) cout << #x << " = " << x << " "; #define prln(x) cout << #x << " = " << x <<endl; #define ll long long struct Node{ int l, r; bool operator < (const Node& rhs)const{ return l > rhs.l || (l == rhs.l && r > rhs.r); } }node[maxn]; bool vis[maxn]; int main(){ #ifdef LOCAL freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin); //freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout); #endif int n, t; scanf("%d", &t); while(t--) { scanf("%d", &n); for(int i = 0; i < n; ++i) { scanf("%d%d", &node[i].l, &node[i].r); vis[i] = 0; } sort(node, node+n); int last = 0, num = INF, ans = 0, cnt = 0, st; while(cnt < n) { ++ans; num = INF; st = last; //prln(last); last = 0; for(int i = st; i < n; ++i) { if(!vis[i]){ if(num >= node[i].r) { num = node[i].r; ++cnt; vis[i] = true; } else if(!last){ last = i; } } } } printf("%d\n", ans); } return 0; }