ZOJ 3953 Intervals

区间删除算法
本文介绍了一种算法问题,即如何通过删除最少数量的区间来确保不存在三个区间两两相交的情况。给出了具体的输入输出示例及代码实现。

Chiaki has n intervals and the i-th of them is [liri]. She wants to delete some intervals so that there does not exist three intervals ab and c such that aintersects with bb intersects with c and c intersects with a.

Chiaki is interested in the minimum number of intervals which need to be deleted.

Note that interval a intersects with interval b if there exists a real number x such that la ≤ x ≤ ra and lb ≤ x ≤ rb.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer n (1 ≤ n ≤ 50000) -- the number of intervals.

Each of the following n lines contains two integers li and ri (1 ≤ li < ri ≤ 109) denoting the i-th interval. Note that for every 1 ≤ i < j ≤ nli ≠ lj or ri ≠rj.

It is guaranteed that the sum of all n does not exceed 500000.

Output

For each test case, output an integer m denoting the minimum number of deletions. Then in the next line, output m integers in increasing order denoting the index of the intervals to be deleted. If m equals to 0, you should output an empty line in the second line.

Sample Input
1
11
2 5
4 7
3 9
6 11
1 12
10 15
8 17
13 18
16 20
14 21
19 22
Sample Output
4

3 5 7 10

题意:删除最少的区间使得三个区间存在一个不相交的两个区间。

思路:三个里面只有两个两两相交,如果三个两两相交就删除右端点最大的边

代码:

#include <iostream>
#include<stdio.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<map>
#include<queue>
#include<vector>
#include<deque>
#define ll long long
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
struct node
{
    int l,r,id;
} a[50005],b[11];
bool cmp(node a,node b)
{
    if(a.l==b.l)
        return a.r<b.r;
    return a.l<b.l;
}
bool cmp1(node a,node b)
{
    return a.r>b.r;
}
bool fun(node a,node b,node c)
{
    return b.l<=a.r&&c.l<=a.r&&c.l<=b.r;
}
int bb[50005];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k=0;
        scanf("%d",&n);
        mem(bb,0);
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&a[i].l,&a[i].r);
            a[i].id=i;
        }
        sort(a+1,a+n+1,cmp);
//        for(int i=1; i<=n; i++)
//        {
//            printf("@%d %d\n",a[i].l,a[i].r);
//        }
        b[0]=a[1];
        b[1]=a[2];
        for(int i=3; i<=n; i++)
        {
            b[2]=a[i];
            sort(b,b+3,cmp);
//            printf("#%d %d\n",b[0].l,b[0].r);
//            printf("##%d %d\n",b[1].l,b[1].r);
//            printf("###%d %d\n",b[2].l,b[2].r);
            if(fun(b[0],b[1],b[2]))
            {
                //printf("##\n");
                sort(b,b+3,cmp1);
                bb[k++]=b[0].id;
                b[0]=b[2];//删除最大的那条边,存在b【2】中下一次会被替换
                //b[1]=b[1];
            }
            else
            {
               sort(b,b+3,cmp1);//删除第一个区间,更新
            }

        }
        printf("%d\n",k);
        sort(bb,bb+k);
        for(int i=0; i<k; i++)
        {
            printf("%d ",bb[i]);
        }
        printf("\n");
    }
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值