当前位置:编程学习 > 网站相关 >>

分组排序

Description
HarryPotter大学毕业后来到了国防部工作。但不幸的是当他工作的第一天,外星人大举入侵地球。HarryPotter被临时调到情报分析部门执行任务。他得到的第一个任务就是对外星人部队的作战能力按从大到小排序。HarryPotter将得到两份情报,一份是外星人每支部队的攻击力,另一份是这些部队的防御力。 
 
当HarryPotter把这些部队按攻击力和防御力分别排好序后,发现有些部队之间是无法比较的,比如两支部队一个攻击力强一些,另一个防御力强一些。HarryPotter将这个信息汇报给了上级,经过一系列商议后上级决定:将所有的部队分为尽可能少的m组,使每组 
内的任意两支部队的作战能力均可以比较,然后再对每组的部队进行排序。(部队A与部队B的作战能力可以比较的充要条件是A的攻击力和防御力均大于B或均小于B) 
 
这下HarryPotter可犯难了,他只知道如何对攻击力或防御力进行排序,但是两者接合到一起就不知如何是好了。请你HarryPotter完成他的任务。 
Input
第一行读入n。其中n表示外星人部队的数目。 
以下有n行,每行有两个正整数Xi,Yi。表示第i支部队的攻击力排在第Xi位,防御力排在第Yi位。(若i!=j,则Xi!=Xj且Yi!=Yj。其中0<Xi,Yi<=n) 
规模:0<n<=100000
Output
文件第一行有一个正整数m。表示给这n支部队排序最少要分成m组。 
以下n行每行有两个正整数k,s。其中第i行表示第i支部队被分在第k组,并且排在第s位。
Sample Input
输入样例1
2
1 2
2 1
输入样例2
5
3 5
5 4
2 1
4 2
1 3
Sample Output
输出样例1
2
1 1
2 1
输出样例2
2
1 2
2 3
2 1
2 2
1 1
 
【分析】
   看到这道题,首先想到的肯定是先排序,再进行操作。那么我们就按照第一关键字从小到大排序(因为题目说了y各不相同,所以y不用排了)。如样例2,排序后是这样
x y
1 3
2 1
3 5
4 2
5 4     不难发现,这样处理后,x是严格单增的,所以对于原条件x单增且y单增便满足了一半。那么只需要对y进行处理便行了。分析后很容易发现可以贪心。
    贪心原则是这样的:顺序讨论排序后的每一个点,然后查找当前点的y。在之前是否有一个在1-y之间的最大值,若有,便将当前点分到与那个最大值的点一个组,然后排名为最大值点的排名加1。否则,便新建一组,置当前点的排名为1。然后添加当前节点。
    这个贪心原则是很显然的,在不用考虑x的情况下(已经拍好序了),y自然是与恰小于他的分在一起所用的组数较小。
    那么再用一个树来完成查找与添加的操作便行了。(蒟蒻只会用线段树写)。
    再回过头来看这道题,其实就是维护每个组的最后一名是谁。然后判断当前节点能否与之前的分在一组。
 
【代码】
 
#include<cstdio>  
#include<cstdlib>  
#include<cstring>  
#include<cmath>  
#include<ctime>  
#include<iostream>  
#include<algorithm>  
using namespace std;  
struct node{  
    int x,y,wjj;  
}v[100005];      //输入数组   
struct ciocio{  
    int loc,rank,wjj;      //wjj是为了离线操作后按照原顺序输出,loc是分组,rank是排名   
}ans[100005];              //答案数组   
int Tree[400005];                    //Tree是线段树,只需要开一个数组,注意空间要为四倍节点大小。   
int N,gr[100005],rank[100005],Max,x;    //gr即group记录每个y的分组,rank记录每个y在结构体v中的下标   
char t[100];  
void _in(int &x)       //输入优化   
{  
    char t=getchar();  
    while(t<'0'||'9'<t) t=getchar();  
    for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar());  
}  
void _out(int &x,int j=1)   //输出优化   
{  
    if(x==0)printf("0");  
    for(;x;x/=10,j++) t[j]=x%10+'0';  
    for(j--;j;j--)putchar(t[j]);  
}  
int _idx(int l,int r)        //找线段树某个区间的编号   
{    
    return ((l+r)|(l!=r));  
}  
bool _cmp_x(node a,node b)      
{  
    return (a.x<b.x);  
}  
bool _cmp_wjj(ciocio a,ciocio b)  
{  
    return (a.wjj<b.wjj);  
}  
void _init()  
{  
    _in(N);  
    for(int i=1;i<=N;i++)  
    {  
        _in(v[i].x);_in(v[i].y);  
        v[i].wjj=i;            //输入时处理编号   
    }  
}  
void _insert(int l,int r)  
{  
    int id,mid;  
    id=_idx(l,r);mid=(l+r)>>1;  
    if(l==r&&r==x)  
    {  
        Tree[id]=x;  
        return;  
    }  
    if(l<r)  
    {  
        if(l<=x&&x<=mid) _insert(l,mid);  
        if(mid+1<=x&&x<=r) _insert(mid+1,r);  
    }  
    Tree[id]=max(Tree[_idx(l,mid)],Tree[_idx(mid+1,r)]);  
}  
void _del(int l,int r)  
{  
    int id,mid;  
    id=_idx(l,r);mid=(l+r)>>1;  
    if(l==r&&r==x)  
    {  
        Tree[id]=0;  
        return;  
    }  
    if(l<r)  
    {  
        if(l<=x&&x<=mid) _del(l,mid);  
        if(mid+1<=x&&x<=r) _del(mid+1,r);  
    }  
    Tree[id]=max(Tree[_idx(l,mid)],Tree[_idx(mid+1,r)]);  
}  
void _findans(int l,int r)               //查找时为查找1-x这一段的最大值   
{  
    int id,mid;  
    id=_idx(l,r);mid=(l+r)>>1;  
    if(1<=l&&r<=x)  
    {  
        Max=max(Max,Tree[id]);             
        return;  
    }  
    if(l<r)  
    {  
        if(!(x<l||mid<1)) _findans(l,mid);  
        if(!(x<mid+1||r<1)) _findans(mid+1,r);  
    }  
    Tree[id]=max(Tree[_idx(l,mid)],Tree[_idx(mid+1,r)]);  
}  
void _solve()  
{  
    int tot=0;  
    sort(v+1,v+1+N,_cmp_x);  
    for(int i=1;i<=N;i++)  
    {  
        Max=0;  
        x=v[i].y;             //Max和x均为全局变量,方便线段树的各项操作   
        rank[x]=i;  
        _findans(1,N);    
        if(Max==0)          //若在1-x这一段没有一个最大值,便新建一个分组   
        {  
            tot++;  
            gr[x]=tot;  
            ans[i].loc=tot;  
            ans[i].rank=1;  
        }  
        else                //若能找到一个在1-x中比他恰小的,便继承那个的分组,然后rank为那个的rank+1;   
        {  
            gr[x]=gr[Max];  
            ans[i].loc=gr[Max];  
            ans[i].rank=ans[rank[Max]].rank+1;  
            x=Max;  
            _del(1,N);  
        }  
        x=v[i].y;  
        _insert(1,N);  
    }  
    for(int i=1;i<=N;i++)          //对应序号后,重新排序   
        ans[i].wjj=v[i].wjj;  
    sort(ans+1,ans+1+N,_cmp_wjj);  
    _out(tot);putchar('\n');  
    for(int i=1;i<=N;i++)  
    {  
        _out(ans[i].loc);putchar(' ');  
        _out(ans[i].rank);putchar('\n');  
    }  
}  
int main()  
{  
    _init();  
    _solve();  
    return 0;  
}  

 

 
补充:综合编程 , 其他综合 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,