Window Area

题意:摘自NOCOW翻译(http://www.nocow.cn/index.php/Translate:USACO/window

描述

你刚刚接手一项窗体界面工程。窗体界面还算简单,而且幸运的是,你不必显示实际的窗体。有 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 的范围内。

[编辑]格式

PROGRAM NAME: window

INPUT FORMAT

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

OUTPUT FORMAT

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

[编辑]SAMPLE INPUT (file window.in)

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


[编辑]SAMPLE OUTPUT (file window.out)

49.167


解题思路:

  1. 参考了NOCOW上(http://www.nocow.cn/index.php/USACO/window)算法一的思想,为每个window保存一个高度值height,添加删除置顶置底的过程中相应修改height值
  2. 求显示面积:初始矩形就是需要求面积的矩形(设高度为h),存入链表中。然后依次用height大于h的矩形分割链表中的矩形,如果能分割则将原矩形删除并添加由于分割而新形成的矩形。具体分割方式可以参考我的另一篇题解(Shaping Regions
  3. 最后的显示面积比例就是链表中所有的小矩形的面积之和除以初始矩形的面积

代码

/*
ID: zc.rene1
LANG: C
PROG: window
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct
{
    int min_x, max_x, min_y, max_y, height;
}window;

FILE *fout;
window chain[62];
int min_height = 0, max_height = 0;
window stack[10000];
int bitmap[10000];

int GetIndex(char c)
{
    /*0~9*/
    if (c >= '0' && c <= '9')
    {
	return c - '0';
    }
    /*A~Z*/
    if (c >= 'A' && c <= 'Z')
    {
	return c - 'A' + 10;
    }
    /*a~z*/
    if (c >= 'a' && c <= 'z')
    {
	return c - 'a' + 36;
    }
    return -1;
}

void CreateWindow(int index, int x1, int y1, int x2, int y2)
{
    int min_x = (x1 < x2) ? x1 : x2;
    int max_x = (x1 > x2) ? x1 : x2;
    int min_y = (y1 < y2) ? y1 : y2;
    int max_y = (y1 > y2) ? y1 : y2;

    chain[index].min_x = min_x;
    chain[index].max_x = max_x;
    chain[index].min_y = min_y;
    chain[index].max_y = max_y;

    chain[index].height = ++max_height;
}

void BringTop(int index)
{
    chain[index].height = ++max_height;
}

void PutBottom(int index)
{
    chain[index].height = --min_height;
}

void Destroy(int index)
{
    chain[index].height = 0;
}

int max(int a, int b)
{
    return a > b ? a : b;
}

int min(int a, int b)
{
    return a < b ? a : b;
}

void Output(int index)
{
    int cur_height = chain[index].height;
    int bottom = -1, top = -1, cur_top, i, j;
    int llx, lly, urx, ury;
    window cn, in;

    memset(bitmap, 0, 10000 * sizeof(int));
    stack[++top] = chain[index];

    for (i=0; i<62; i++)
    {
	in = chain[i];
	if (in.height != 0 && in.height > cur_height)
	{
	    cur_top = top;

	    for (j=bottom+1; j<=cur_top; j++)
	    {
		cn = stack[j];

		llx = max(in.min_x, cn.min_x);
		lly = max(in.min_y, cn.min_y);
		urx = min(in.max_x, cn.max_x);
		ury = min(in.max_y, cn.max_y);

		if (bitmap[j] == 1 || urx <= llx || ury <= lly)
		{
		    continue;
		}
		bitmap[j] = 1;

		if (llx > cn.min_x && cn.max_y > lly)
		{
		    top++;
		    stack[top].min_x = cn.min_x;
		    stack[top].min_y = lly;
		    stack[top].max_x = llx;
		    stack[top].max_y = cn.max_y;
		    stack[top].height = cn.height;
		}

		if (cn.max_x > llx && cn.max_y > ury)
		{
		    top++;
		    stack[top].min_x = llx;
		    stack[top].min_y = ury;
		    stack[top].max_x = cn.max_x;
		    stack[top].max_y = cn.max_y;
		    stack[top].height = cn.height;
		}
		
		if (cn.max_x > urx && ury > cn.min_y)
		{
		    top++;
		    stack[top].min_x = urx;
		    stack[top].min_y = cn.min_y;
		    stack[top].max_x = cn.max_x;
		    stack[top].max_y = ury;
		    stack[top].height = cn.height;
		}

		if (urx > cn.min_x && lly > cn.min_y)
		{
		    top++;
		    stack[top].min_x = cn.min_x;
		    stack[top].min_y = cn.min_y;
		    stack[top].max_x = urx;
		    stack[top].max_y = lly;
		    stack[top].height = cn.height;
		}
	    }
	}
    }

    double sum = 0.0;
    for (i=bottom+1; i<=top; i++)
    {
	if (bitmap[i] == 0)
	{
	    cn = stack[i];
	    sum += (cn.max_x - cn.min_x) * (cn.max_y - cn.min_y);
	}
    }
    fprintf(fout, "%.3lf\n", 100 * sum / ((chain[index].max_x - chain[index].min_x) * (chain[index].max_y - chain[index].min_y)));
}

void DoJob(char *str)
{
    char c, i;
    int index, x1, y1, x2, y2;

    sscanf(str, "%c(%c, ", &c, &i);
    index = GetIndex(i);
    switch(c)
    {
	case 'w':
	    sscanf(str, "%c(%c, %d, %d, %d, %d)\n", &c, &i, &x1, &y1, &x2, &y2);
	    CreateWindow(index, x1, y1, x2, y2);
	    break;
	case 't':
	    sscanf(str, "%c(%c)\n", &c, &i);
	    BringTop(index);
	    break;
	case 'b':
	    sscanf(str, "%c(%c)\n", &c, &i);
	    PutBottom(index);
	    break;
	case 'd':
	    sscanf(str, "%c(%c)\n", &c, &i);
	    Destroy(index);
	    break;
	case 's':
	    sscanf(str, "%c(%c)\n", &c, &i);
	    Output(index);
	    break;
	default:
	    printf("Wrong input (%s)\n", str);
	    break;
    }
}

int main(void)
{
    FILE *fin;
    char str[100];

    fin = fopen("window.in", "r");
    fout = fopen("window.out", "w");

    memset(chain, 0, 62 * sizeof(window));
    while (fgets(str, 100, fin) != NULL)
    {
	DoJob(str);
    }
    return 0;
}




QScrollArea 是一个 Qt 常用的可滚动区域控件,它可以在需要显示大量内容但又不想占用过多屏幕空间时使用。QScrollArea 可以包含一个 widget,并在 widget 的大小大于 QScrollArea 大小时提供滚动条来浏览 widget 内容。 使用 QScrollArea 可以实现很多场景,比如在一个窗体中显示一张很大的图片、显示一个文本编辑器、显示大量数据等等。 使用 QScrollArea 控件的基本步骤如下: 1. 创建一个 QScrollArea 控件。 2. 创建一个 widget ,并将其设置为 QScrollArea 的子控件。 3. 设置 widget 的大小,并且将 widget 中需要显示的内容添加到 widget 中。 4. 将 widget 设置为 QScrollArea 的 viewport。 5. 如果需要,可以设置 QScrollArea 的滚动条策略。 以下是一个简单示例: ```python from PyQt5.QtWidgets import QApplication, QWidget, QScrollArea, QVBoxLayout, QLabel app = QApplication([]) window = QWidget() scroll_area = QScrollArea() widget = QWidget(scroll_area) layout = QVBoxLayout(widget) for i in range(50): label = QLabel(f"Label {i}") layout.addWidget(label) widget.setLayout(layout) scroll_area.setWidgetResizable(True) scroll_area.setWidget(widget) main_layout = QVBoxLayout(window) main_layout.addWidget(scroll_area) window.setLayout(main_layout) window.show() app.exec_() ``` 在上面的示例中,我们创建了一个 QWidget 控件作为 QScrollArea 的子控件,然后在这个 widget 中添加了 50 个 QLabel 控件。最后将 widget 设置为 QScrollArea 的 viewport,并设置 QScrollArea 可以改变 widget 大小。这样就可以通过滚动条来浏览 widget 中的内容了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值