Shaping Regions

题意:N个不同颜色的矩形依次被堆放在一个宽A长B的矩形白纸上,求俯视视角中各种颜色所占的面积。


解题思路

  1. 受HINT 1 启发,如果一个矩形与前面的矩形有重叠,那么就会将前面的矩形分割为几块,参见NOCOW(http://www.nocow.cn/index.php/USACO/rect1)中矩形切割部分。如下图阴影部分为矩形与前一个矩形的重叠部分。
  2. 用一个链表保存已有的矩形。每次堆放一个新的矩形input[5](五个元素分别为左下角坐标、右上角坐标,还有颜色)的时候,将其与这个链表中的每一个矩形cn[5]进行重叠检测。按照上图,重叠部分左下角坐标(llx, lly),右上角坐标(urx, ury)。那么
    llx = max(input[0], cn[0]);
    lly = max(input[1], cn[1]);
    urx = min(input[2], cn[2]);
    ury = min(input[3], cn[3]);
  3. 如果urx <= llx 或者 ury <= lly,那么没有重叠部分,继续判断链表中下一个矩形
  4. 如果有重叠部分,那么首先删去这个被覆盖的矩形。然后按照图中标注的,将新生成的1, 2, 3, 4四个矩形加入链表。注意这4个矩形也许要按照第3步中的逻辑判断左下角和右上角的坐标是否正常,如果为正常则将其加入链表,否则不加入。
  5. 最后要将这个堆放在最上层的矩形加入链表。
  6. 重复2~5,直到最后一个矩形被堆叠上去。那么这个链表中的矩形就是最后俯视图的结果,链表中的矩形覆盖了整个A*B的坐标区域并且没有重叠。
  7. 遍历一遍链表,统计并输出最终结果

代码

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

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

struct rectangle
{
    int llx, lly, urx, ury, color;
    struct rectangle *next;
};


void CountColor(struct rectangle *head, int *color_count)
{
    memset(color_count, 0, 1001*sizeof(int));
    if (head == NULL)
    {
	return ;
    }

    head = head->next;

    while (head != NULL)
    {
	color_count[head->color] += ((head->urx - head->llx) * (head->ury - head->lly));
	head = head->next;
    }
}

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

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

void InsertNode(int *input, struct rectangle *current)
{
    struct rectangle *temp = (struct rectangle *)malloc(sizeof(struct rectangle));
    memcpy(temp, input, 5*sizeof(int));
    temp->next = current->next;
    current->next = temp;
}

void DeleteNode(struct rectangle *prev, struct rectangle **current)
{
    struct rectangle *temp = *current;
    prev->next = (*current)->next;
    *current = prev;
    free(temp);
}

void InsertRectangle(int *input, struct rectangle *head)
{
    struct rectangle *current = head;
    struct rectangle *prev = NULL;
    int cn[5];
    int in[5];
    int llx, lly, urx, ury;

    while (current->next != NULL)
    {
	prev = current;
	current = current->next;

	memcpy(cn, current, 5*sizeof(int));
	llx = max(input[0], cn[0]);
	lly = max(input[1], cn[1]);
	urx = min(input[2], cn[2]);
	ury = min(input[3], cn[3]);

	if ((urx <= llx) || (ury <= lly))
	{
	    continue;
	}
	DeleteNode(prev, ¤t);
	/*insert 1*/
	if ((llx > cn[0]) && (cn[3] > lly))
	{
	    in[0] = cn[0];
	    in[1] = lly;
	    in[2] = llx;
	    in[3] = cn[3];
	    in[4] = cn[4];
	    InsertNode(in, current);
	}
	/*insert 2*/
	if ((cn[2] > llx) && (cn[3] > ury))
	{
	    in[0] = llx;
	    in[1] = ury;
	    in[2] = cn[2];
	    in[3] = cn[3];
	    in[4] = cn[4];
	    InsertNode(in, current);
	}
	/*insert 3*/
	if ((cn[2] > urx) && (ury > cn[1]))
	{
	    in[0] = urx;
	    in[1] = cn[1];
	    in[2] = cn[2];
	    in[3] = ury;
	    in[4] = cn[4];
	    InsertNode(in, current);
	}
	/*insert 4*/
	if ((urx > cn[0]) && (lly > cn[1]))
	{
	    in[0] = cn[0];
	    in[1] = cn[1];
	    in[2] = urx;
	    in[3] = lly;
	    in[4] = cn[4];
	    InsertNode(in, current);
	}
    }
    InsertNode(input, current);
}

int main(void)
{
    FILE *fin, *fout;
    int A, B, N;
    int input[1001][5];
    struct rectangle *tail = NULL;
    struct rectangle *head = NULL;
    int i, j, color, temp;
    int color_count[1001];

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

    /*get input*/
    fscanf(fin, "%d %d %d", &A, &B, &N);
    input[0][0] = 0;
    input[0][1] = 0;
    input[0][2] = A;
    input[0][3] = B;
    input[0][4] = 1;

    for (i=1; i<=N; i++)
    {
	for (j=0; j<5; j++)
	{
	    fscanf(fin, "%d", &input[i][j]);
	}
    }
    /*begin to insert*/
    head = (struct rectangle *)malloc(sizeof(struct rectangle));
    for (i=0; i<=N; i++)
    {
	InsertRectangle(input[i], head);
    }
    /*get the count of each color*/
    CountColor(head, color_count);
    for (i=0; i<1001; i++)
    {
	if (color_count[i] != 0)
	{
	    fprintf(fout, "%d %d\n", i, color_count[i]);
	}
    }
    return 0;
}































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值