[漂浮法]CSU1589 Shaping Regions

漂浮法主要用于解决一类矩形线段覆盖问题,比如求覆盖后的面积,可见数量等,可以水过一些扫描线题,而且比较好写。
原理类比把矩形按照顺序从底到顶的放进水里,然后让下面的依次上浮,过程中如果被其他矩形挡住就分裂成几个矩形继续上浮,最后到顶的就是这个矩形最后可以看见的部分。

过程用DFS实现。

具体看代码。

最坏复杂度O(n^2),但是常数小,配合2个剪枝,在OJ跑8ms,和扫描线时间差不多,省去了建树的空间。

最坏深度是N,一般的数据不会爆栈,但是如果数据估计卡,每次DFS到最深的话,时间就和n^2差不多了。

两个剪枝是很容易想到的。

#include<cstring>
#include<cstdio>
struct node{
    int x1,y1,x2,y2,col;
}p[1005];
int max(int &a,int &b){return a>b?a:b;}
int min(int &a,int &b){return a>b?b:a;}
int n;
int ans[2505];
bool vis[2505];
void pf(int x1,int y1,int x2,int y2,int col,int c) //x1y1为左下的坐标 x2y2为右上的坐标
{
    if(x1>=x2||y1>=y2) return; //剪枝1 现在的范围已经不存在了
    while(c<=n&&((x2<=p[c].x1)||(y2<=p[c].y1)||(x1>=p[c].x2)||(y1>=p[c].y2))) 
        c+=1; //剪枝2 如果现在的范围和当前判断的矩形不相交就直接判下一个 不加这个犀利的剪枝大概400ms
    if(c>n) {
            ans[col]+=(x2-x1)*(y2-y1); 
            return; 
    }
    if(y1<p[c].y1) pf(max(p[c].x1,x1),y1,max(p[c].x1,x2),min(p[c].y1,y2),col,c+1);
    if(y2>p[c].y2) pf(min(x1,p[c].x2),max(y1,p[c].y2),min(p[c].x2,x2),y2,col,c+1);
    if(x1<p[c].x1) pf(x1,min(p[c].y2,y1),min(p[c].x1,x2),min(p[c].y2,y2),col,c+1);
    if(x2>p[c].x2) pf(max(p[c].x2,x1),max(p[c].y1,y1),x2,max(p[c].y1,y2),col,c+1);
}
int main(){
    int T;
    scanf("%d",&T);
    p[0].x1=p[0].y1=0,p[0].col=1;
    while(T--){
        scanf("%d%d%d",&p[0].x2,&p[0].y2,&n); //把整个范围看成一个矩形
        memset(vis,0,sizeof(vis));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;++i) {
                scanf("%d%d%d%d%d",&p[i].x1,&p[i].y1,&p[i].x2,&p[i].y2,&p[i].col);
                vis[p[i].col]=1;
        }
        vis[1]=1;
        for(int i=0;i<=n;++i) pf(p[i].x1,p[i].y1,p[i].x2,p[i].y2,p[i].col,i+1);
        for(int i=1;i<=2505;++i) 
        {
            if(vis[i]&&ans[i]) printf("%d %d\n",i,ans[i]);
        }
    }
}

你可能感兴趣的:(ACM,CSU)