[USACO5.3.2] 窗体面积 - 矩形切割

该博客介绍了USACO题目5.3.2中关于窗体界面管理的问题,涉及矩形切割算法。文章讨论了如何处理创建、置顶、置底、删除窗体的操作,并对窗体可见部分的百分比进行计算。通过维护一个队列,对窗体进行操作,并在查询时进行矩形切割的统计,最终输出窗体的可见比例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题目描述

你刚刚接手一项窗体界面工程。窗体界面还算简单,而且幸运的是,你不必显示实际的窗体。有 5 种基本操作:

  创建一个新窗体
  将窗体置顶
  将窗体置底
  删除一个窗体
输出窗体可见部分的百分比(就是,不被其它窗体覆盖的部分)。
在输入文件中,操作以如下的格式出现。

  创建一个新窗体:w(I,x,y,X,Y)
  将窗体置顶: t(I)
  将窗体置底: b(I)
  删除一个窗体:d(I)
  输出窗体可见部分的百分比:s(I)
I 是每个窗体唯一的标识符。表示符可以是 ‘a’..’z’, ‘A’..’Z’ 和 ‘0’..’9’ 中的任何一个。输入文件中没有多余的空格。
(x,y)和(X,Y)是窗体的对角。当你创建一个窗体的时候,它自动被“置顶”。你不能用已经存在的标识符来创建窗体,但是你  可以删除一个窗体后再用已删除窗体的标识符来创建窗体。坐标用正整数来表示,并且所有的窗体面积都不为 0(x <> X 且 y <> Y)。x 坐标和 y 坐标在 1 —— 32767 的范围内。


输入格式

输入文件包含给你的解释程序的一系列命令,每行一个。当输入文件结束时,停止程序。


输出格式

只对于 s() 命令进行输出。当然,输入文件可能有许多 s() 命令,所以输出文件应该是一个百分比的序列,每行一个,百分比是窗体可见部分的百分比。百分比应该四舍五入到三位小数。


样例数据

样例输入

w(a,10,132,20,12)
w(b,8,76,124,15)
s(a)

样例输出

49.167


说明

插入操作不超过150
总操作次数不超过1000


题目分析

这应该算是usaco史上最为恶心的调试题了吧(当然素数方阵更厉害)
对于每一个窗体看做一个矩形
维护一个队列
新加的窗体加入队尾
如果要置顶一个窗体,将他从队列中转到队尾
如果要置底一个窗体,将他从队列中转到队首
如果删除一个窗体,将他从队列中删除
以上操作均不用加入切割

如果查询,那么将队列中所有窗体顺序进行切割,统计面积
查询完毕后清空矩形切割中的矩形


源代码

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
inline const int Get_Int() {
    int num=0,bj=1;
    char x=getchar();
    while(x<'0'||x>'9') {
        if(x=='-')bj=-1;
        x=getchar();
    }
    while(x>='0'&&x<='9') {
        num=num*10+x-'0';
        x=getchar();
    }
    return num*bj;
}
struct Square {
    double x1,x2,y1,y2;
    char uuid;
    Square() {}
    Square(double lx,double ly,double rx,double ry,char color):x1(lx),y1(ly),x2(rx),y2(ry),uuid(color) {}
};
struct Cut_Square {
    Square a[100005];
    int sum;
    int init() {
        sum=0;
    }
    bool if_intersect(Square a,Square b) {
        if(a.x1>=b.x2||a.y1>=b.y2||a.x2<=b.x1||a.y2<=b.y1)return false;
        else return true;
    }
    void add(double x1,double y1,double x2,double y2,char uuid) {
        a[++sum]=Square(x1,y1,x2,y2,uuid);
    }
    void del(int index) {
        a[index]=a[sum];
        sum--;
    }
    double Xway_cut(int index,double x1,double y1,double x2,double y2) { //返回交集
        double k1=max(x1,a[index].x1);
        double k2=min(x2,a[index].x2);
        if(a[index].x1<k1)add(a[index].x1,a[index].y1,k1,a[index].y2,a[index].uuid);
        if(k2<a[index].x2)add(k2,a[index].y1,a[index].x2,a[index].y2,a[index].uuid);
        return Yway_cut(index,k1,y1,k2,y2);
    }
    double Yway_cut(int index,double x1,double y1,double x2,double y2) {
        double k1=max(y1,a[index].y1);
        double k2=min(y2,a[index].y2);
        if(a[index].y1<k1)add(x1,a[index].y1,x2,k1,a[index].uuid);
        if(k2<a[index].y2)add(x1,k2,x2,a[index].y2,a[index].uuid);
        return (x2-x1)*(k2-k1);
    }
};
struct QueNode {
    char uuid;
    int x1,y1,x2,y2;
    QueNode() {}
    QueNode(char u,int lx,int ly,int rx,int ry):uuid(u),x1(lx),y1(ly),x2(rx),y2(ry) {}
} Q[500005];
Cut_Square s;
int Right=0;
int main() {
    char order,uuid;
    while(scanf("%c",&order)!=EOF) {
        if(order=='w') { //加入
            int x1,y1,x2,y2;
            scanf("(%c,%d,%d,%d,%d)",&uuid,&x1,&y1,&x2,&y2);
            int tx1=x1,ty1=y1,tx2=x2,ty2=y2;
            x1=min(tx1,tx2);
            y1=min(ty1,ty2);
            x2=max(tx1,tx2);
            y2=max(ty1,ty2);
            Q[++Right]=QueNode(uuid,x1,y1,x2,y2); //窗体入队
        } else if(order=='t') { //置顶
            int pos;
            scanf("(%c)",&uuid);
            for(int i=1; i<=Right; i++) //移动队列,将指定窗口放到队尾
                if(Q[i].uuid==uuid) {
                    pos=i;
                    break;
                }
            QueNode Now=Q[pos];
            for(int i=pos; i<Right; i++)Q[i]=Q[i+1];
            Q[Right]=Now;
        } else if(order=='b') { //置底
            int pos;
            scanf("(%c)",&uuid);
            for(int i=1; i<=Right; i++) //移动队列,将指定窗口放到队首
                if(Q[i].uuid==uuid) {
                    pos=i;
                    break;
                }
            QueNode Now=Q[pos];
            for(int i=pos-1; i>=1; i--)Q[i+1]=Q[i];
            Q[1]=Now;
        } else if(order=='d') { //删除
            int pos;
            scanf("(%c)",&uuid);
            for(int i=1; i<=Right; i++)
                if(Q[i].uuid==uuid) {
                    pos=i;
                    break;
                }
            for(int i=pos; i<Right; i++)Q[i]=Q[i+1];
            Right--;
        } else if(order=='s') { //询问
            int pos;
            double sum=0;
            scanf("(%c)",&uuid);
            for(int i=1; i<=Right; i++)
                if(Q[i].uuid==uuid) {
                    pos=i;
                    break;
                }
            for(int i=1; i<=Right; i++) { //依次添加窗体 
                Square b=Square(Q[i].x1,Q[i].y1,Q[i].x2,Q[i].y2,Q[i].uuid);
                for(int j=1; j<=s.sum; j++) {
                    if(!s.if_intersect(s.a[j],b))continue; //不相交
                    s.Xway_cut(j,b.x1,b.y1,b.x2,b.y2);
                    s.del(j);
                    j--; //删除完矩形移动了最后一个矩形,若j不-1可能导致原矩形未切割
                }
                s.add(b.x1,b.y1,b.x2,b.y2,b.uuid);
            }
            for(int i=1; i<=s.sum; i++)
                if(s.a[i].uuid==uuid)sum+=(s.a[i].x2-s.a[i].x1)*(s.a[i].y2-s.a[i].y1);
            printf("%0.3lf\n",sum*100/((Q[pos].x2-Q[pos].x1)*(Q[pos].y2-Q[pos].y1)));
            s.init(); //清空矩阵切割数组 
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值