• POJ2528的另一种解法(线段切割)



    题目:Mayor's posters

    原文地址

    首先本题题意是:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度。现在往墙上贴N张海报,每张海报的宽度是任意

    的,但是必定是单位宽度的整数倍,且<=1QW。后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海

    报。现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?

     

    利用线段切割,由于后贴的海报可能会覆盖前面的,而很明显知道前面的海报不会影响后面海报的可见性,所以应该从后面往

    前面推。

     

    所以程序中就有:for(i=n-1;i>=0;i--)   

    现在我们暂时只分析前一张海报与后一张海报的关系就可以了,然后递推就可以了。

    我们用海报的长度来表示可见性,如果长度大于0,当然就可见啊

    对于海报之间的关系,只有那么几种情况,但是看程序中只有3种关系,实际上在统计可见性时我们说只需要3种就够了,为什

    么呢?

     

    我们可以自己模拟一下:

    如果两张海报没有交集,那么下面的那张海报一定是可见的,所以长度当然大于0,

    如果两张海报有交集,就必然有4种关系,但是这里我们相当于只有两种就够了,就是后面的覆盖前面的右半部分,或者后面的

    覆盖前面的左半部分,注意我们开始memset所有的海报长度是0,所以如果出现后面的海报全部覆盖前面的海报的情况就不用

    管,因为它就是0,但是还有一种关系,就是后面的海报覆盖前面海报的中间部分,这样的话我们就可以把它当成覆盖左边部分

    或者覆盖右边部分,因为我们的判断语句是

     if(l<node[k].x) 

     if(r>node[k].y)   

    很明显可以看出实际上这两个语句包含了3种情况。而不仅仅代表只覆盖右部分或者左部分。

    这样我们在结构体里面用ans统计每张海报最终的长度,实际上不一定是真正的长度哈,比如后一张只覆盖前一张的和中间部分

    的那一种情况,实际上ans就只记录了前面的海报的左边部分,所以这样本题就解决了,线段切割实现起来更容易。

    注意线段切割与矩形切割适用的范围:对边界范围大,操作数少的题目,我们选择矩形切割或者线段切割。 

    #include <stdio.h>  
    #include <string.h>  
      
    const int N = 10005;  
      
    typedef struct  
    {  
        int x,y;  
        int ans;  
    }Node;  
      
    Node node[N];  
      
    int n;  
      
    void Cover(int l,int r,int k,int c)  
    {  
        while(k<n&&(r<node[k].x||l>node[k].y)) k++;  
        if(k>=n)        //当前进行切割的线段并没有和后面的线段相交  
        {  
            node[c].ans+=r-l+1;  
            return;  
        }  
        if(l<node[k].x) Cover(l,node[k].x-1,k+1,c);   //当前线段的右边被覆盖;  
        if(r>node[k].y) Cover(node[k].y+1,r,k+1,c);   //当前线段的左边被覆盖;  
    }  
      
    int main()  
    {  
        int t,i,sum;  
        scanf("%d",&t);  
        while(t--)  
        {  
            sum=0;  
            memset(node,0,sizeof(node));  
            scanf("%d",&n);  
            for(i=0;i<n;i++)  
                scanf("%d%d",&node[i].x,&node[i].y);  
            for(i=n-1;i>=0;i--)            //这里是用后面的海报覆盖前面的海报,所以要从后面开始进行插入(进行线段切割);  
                Cover(node[i].x,node[i].y,i+1,i);  
            for(i=0;i<n;i++)  
                if(node[i].ans>0)  
                    sum++;  
            printf("%d
    ",sum);  
        }  
        return 0;  
    }  
    


    today lazy . tomorrow die .
  • 相关阅读:
    HWOJ之纠结的优化
    java中的对象数组
    短路特性的运用
    归并排序
    两个有序数列的合并
    java中的注释规范
    堆排序
    堆的建立
    希尔排序
    直接插入排序
  • 原文地址:https://www.cnblogs.com/france/p/4808781.html
Copyright © 2020-2023  润新知