Final Exam Arrangement

题目链接

  • 题意:
    输入n个左闭右开的线段,如果两个线段有重叠部分,那么这两个线段必然不能在一组。求,最少分几组,并且输出每组都有谁
  • 分析:
    将一个线段拆开成左右端点,排序。从左向右扫描,如果遇到的是左端点,那么直接加入到集合中,此时集合中的这些线段两两有重合部分,所以是可以分到同一组的;如果遇到的是右端点,那么当前线段之后将和当前线段没有重合点,必然不能放到一组。这样贪心的将每一个线段尽可能的分到一个组中(分到哪个组无所谓,只要分到了一个组中,答案就能减少),就可以保证答案是最少的。当一个线段不能分到前一个组中,必然是和前一个组中的某条线段冲突,所以保证了正确性。
const int MAXN = 1100000;

struct Node
{
    int v, id, isr;
    int operator< (const Node& rhs) const
    {
        if (v != rhs.v)
            return v < rhs.v;
        else
            return isr > rhs.isr;
    }
} ipt[MAXN];

VI ans[MAXN];
int vis[MAXN];

int main()
{
    int n, l, r;
    while (~RI(n))
    {
        CLR(vis, 0);
        REP(i, MAXN)
            ans[i].clear();
        REP(i, n)
        {
            RII(l, r);
            int x = i << 1, y = x | 1;
            ipt[x].isr = 0;
            ipt[x].v = l;
            ipt[y].isr = 1;
            ipt[y].v = r;
            ipt[x].id = ipt[y].id = i + 1;
        }
        n <<= 1;
        sort(ipt, ipt + n);
        int val = 0;
        REP(i, n)
        {
            if (ipt[i].isr)
            {
                if (vis[ipt[i].id] != val)
                    continue;
                val++;
            }
            else
            {
                ans[val].push_back(ipt[i].id);
                vis[ipt[i].id] = val;
            }
        }
        WI(val);
        REP(i, val) REP(j, ans[i].size())
            printf("%d%c", ans[i][j], j == (int)ans[i].size() - 1 ? '\n' : ' ');
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值