ZOJ 3953 Intervals (贪心/区间交)

来源:互联网 发布:最赚钱的网络投资 编辑:程序博客网 时间:2024/05/16 17:20

题意

给定一些区间,要求删除一些区间使得任意取三个区间不会出现两两相交的情况

思路

先将区间按左端点从小到大排序,遇到出现三个区间两两相交的情况时,显然删掉最靠右的区间会比删掉其他两个更优
如何判断当前有三个区间两两相交呢?
(参考同学的思路)我们可以维护一个缓冲区间,区间里的元素按照右端点从大到小排序,如果新的区间的左端点大于区间最后一个元素的右端点,因为是按照左端点排序扫描的,那么就不用再考虑最后一个元素。当区间中元素有3个时,就可以确定这3个区间两两相交(只要是新加入缓冲区的区间,一定和之前在的区间相交,因为大于之前所有区间的左端点,小于最小的右端点)

代码

#include <bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))#define rep(i,a,b) for(int i=a;i<b;i++)const int INF=0x3f3f3f3f;const int maxn=5e4+50;const int mod=1e9+7;#define pii pair<int,int>typedef long long ll;typedef unsigned int ui;using namespace std;struct Node{    int id,l,r;    bool operator<(const Node &rhs)const{        if(l!=rhs.l) return l<rhs.l;        return r<rhs.r;    }};int n;Node s[maxn];bool cmpRG(const Node&a,const Node&b){    return a.r>b.r;}bool cmpRB(const Node&a,const Node&b){    return a.r<b.r;}int main(){#ifndef ONLINE_JUDGE    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);#endif    int T; scanf("%d",&T);    while(T--){        scanf("%d",&n);        rep(i,0,n){            s[i].id=i+1;            scanf("%d %d",&s[i].l,&s[i].r);        }        sort(s,s+n);        vector<int> ans;        Node buf[3];        int pos=0;        rep(i,0,n){            //printf("%d %d %d\n",s[i].id,s[i].l,s[i].r);            sort(buf,buf+pos,cmpRG);            if(pos && buf[pos-1].r<s[i].l) pos--;            buf[pos++]=s[i];            if(pos==3){                sort(buf,buf+pos,cmpRB);                ans.push_back(buf[2].id);                pos--;            }        }        sort(ans.begin(),ans.end());        printf("%d\n",ans.size());        for(int i=0;i<ans.size();i++){            if(i==0) printf("%d",ans[i]);            else printf(" %d",ans[i]);        }        puts("");    }    return 0;}
0 0
原创粉丝点击