SOJ 1045

1045. Space Management

Constraints

Time Limit: 1 secs, Memory Limit: 32 MB

Description

The new general manager Gill Bates has been to a seminar on time management. Ever since she has been bothering all of her staff to manage their own time. Now she plans to take it one step further: she wants to start managing her space too. And since she has also learned to start small, she wants to start by managing her desk space. Work tends to pile up on her desk, especially since the time management training where she was taught to order all documents in neat piles and organize her work accordingly. She now needs to calculate how much desk space is occupied. For this she comes up with a cunning plan. First, she orders her staff to measure the size and exact location of each document on the desk, in tenths of millimeters accuracy. As Gill is a very tidy person, all her document are completely on her desk, and are all perfectly aligned to the edges of the desk (i.e. the edges of all documents are parallel to an edge of the desk). For each document, the staff writes down the position of the lower left corner of the document and its size. 
What you need to do now is to write a program that, given the input from the staff, calculates the occupied space on the desk. The maximum size of the desk is 2 * 1 meters. There is a maximum of 500 documents on the desk. 

Input

The first line of the input consists of the number N of desks to be considered. Next follows for each desk the number of documents. Then follows for each document a separate line with 4 numbers: the smallest X and Y co-ordinates (i.e. the lower left corner), and the width and height of the document respectively.

Output

The output consists of N lines containing the amount of occupied space on each desk in squared tenths of millimeters.

Sample Input

2
2
0 0 1000 1000
0 0 1000 1000
3 
0 0 2 2 
2 2 2 2 
1 1 2 2

Sample Output

1000000

10

要求桌子被文件覆盖的总面积,最大难点就是处理重叠,如果将桌子和文件化为一维,即桌子是一条长线,而每个文件占用一定的长度,这样来求总占用长度的话就可以将所有文件按占用长度的起始点排序,再设一个变量R来保存之前已计算过文件的最右端位置,这样当我们要计算下一个文件的占用长度时就可以通过比较下个文件的起终点和之前文件的最右端位置来判定它与之前文件的重叠程度,然后就可以很快捷的求出总的占用长度。但当问题推广到二维的时候情况就复杂了许多,所以我们可以将二维化成一维,桌子是1000行2000列,我们可以分行计算,每一行就是一个一维结构,然后对于某一行,我们知道每个文件在这一行所覆盖的长度及起点,然后根据上面的方法就可以求出所有文件在这一行覆盖的长度(这里长度和面积是等价的,因为二维数组中每一格就是一个单位面积),同理可以求出每一行被覆盖的长度,然后进行累加就是整个桌子被覆盖的面积。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct node{
	int start;//每一行被覆盖的起点 
	int length;//覆盖的长度 
	node(int s,int l)
	{
		start=s;
		length=l;
	}
};
int N,numOfDoc;//N为桌子数,numOfDoc为文件数 
int x,y,width,height;//保存文件的位置 
vector<node> desk[1000];//可以用二维数组来模拟桌子,但用容器数组会更方便一点 
int occupied[1000];//记录桌子每行被占用的面积(2000*1000的桌子,将其看成2000列1000行) 
bool cmp(node A,node B)//比较函数,按每行覆盖的起点排序 
{
	return A.start<B.start;
}
void saveData()//分行存储数据 
{
	for(int i=0;i<numOfDoc;++i)
	{
		cin>>x>>y>>width>>height;
		for(int j=x;j<x+height&&j<1000;++j)//文件覆盖x至x+height-1行,每行覆盖的起点为y,覆盖长度为width 
		{
			desk[j].push_back(node(y,width));
		}
	}
}
int caculate()//分行计算覆盖面积 
{
	memset(occupied,0,sizeof(occupied));
	for(int i=0;i<1000;++i)
	{
		if(desk[i].size())//若这一行有覆盖 
		{
		
			sort(desk[i].begin(),desk[i].end(),cmp);//先将各个覆盖按起始点排序	
			int Max=desk[i][0].start+desk[i][0].length-1; //Max记录当前已计算过的覆盖的最右端 
			occupied[i]+=desk[i][0].length;//第i行的第一个覆盖自然是全部计入 
			for(int j=1;j<desk[i].size();++j)//从第二个覆盖开始分类讨论 
			{
				if(desk[i][j].start>Max) //若这一覆盖左端大于之前所有覆盖的最右端,自然全部计入,并更新新的最右端 
				{
					occupied[i]+=desk[i][j].length;
					Max=desk[i][j].start+desk[i][j].length-1;
				}
				else if(desk[i][j].start+desk[i][j].length-1<=Max) continue;//若这一覆盖的最右端还小于之前覆盖的最右端,自然与之前的覆盖完全重合,所有不用再计算 
				else //若只有部分重叠,则只计算不重叠的部分,并更新最右端 
				{
					occupied[i]+=desk[i][j].start+desk[i][j].length-1-Max;
					Max=desk[i][j].start+desk[i][j].length-1;
				}
			}
			//这样就计算出了桌子某一行被覆盖的面积,直至算出所有行被覆盖的面积 
			
		}
	}
	int ans=0;
	for(int i=0;i<1000;++i)
	{
		ans+=occupied[i];//每一行被覆盖的面积相加即是总覆盖面积 
	}
	return ans;
}
int main()
{
	cin>>N;
	for(int i=0;i<N;++i)
	{
		cin>>numOfDoc;
		for(int j=0;j<1000;++j)
		    desk[j].clear();
		saveData();
		cout<<caculate()<<endl;
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值