hdu-2461-Rectangles(容斥)

Rectangles

Time Limit: 5000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)


Problem Description
You are developing a software for painting rectangles on the screen. The software supports drawing several rectangles and filling some of them with a color different from the color of the background. You are to implement an important function. The function answer such queries as what is the colored area if a subset of rectangles on the screen are filled.
 


Input
The input consists of multiple test cases. Each test case starts with a line containing two integers N(1 ≤ N ≤ 20) and M(1 ≤ M ≤ 100000), indicating the number of rectangles on the screen and the number of queries, respectively.
The i-th line of the following N lines contains four integers X1,Y1,X2,Y2 (0 ≤ X1 < X2 ≤ 1000, 0 ≤ Y1 < Y2 ≤ 1000), which indicate that the lower-left and upper-right coordinates of the i-th rectangle are (X1, Y1) and (X2, Y2). Rectangles are numbered from 1 to N.
The last M lines of each test case describe M queries. Each query starts with a integer R(1<=R ≤ N), which is the number of rectangles the query is supposed to fill. The following list of R integers in the same line gives the rectangles the query is supposed to fill, each integer of which will be between 1 and N, inclusive.


The last test case is followed by a line containing two zeros.
 


Output

For each test case, print a line containing the test case number( beginning with 1).
For each query in the input, print a line containing the query number (beginning with 1) followed by the corresponding answer for the query. Print a blank line after the output for each test case.
 

Sample Input

2  2
0 0 2 2
1 1 3 3
1 1
2 1 2
2 1
0 1 1 2
2 1 3 2
2 1 2
0 0
 
Sample Output

Case 1:
Query 1: 4
Query 2: 7


Case 2:
Query 1: 2


题意:

给定n个矩形的左下角坐标和右上角的坐标,接下来m次询问,每次有一cnt,表示后面有多少个矩形,接下来又cnt个矩形的编号(1开始),问这cnt个矩形“并”的面积。


题目链接:Rectangles


解题思路:
n个矩形的面积并 = n个矩形的面积 - n个矩形中2个相交后的矩形面积 +n个矩形中3个相交后的矩形面积.....
很明显的可以用容斥操作,枚举矩形和其它矩形尝试相交,如果能相交,则传递相交后的矩形继续尝试与其他矩
形相交,保留这个新的矩形是由几个矩形相交产生的即可。
矩形相交的判定可以根据两矩形重心之间的距离来判断,只有横坐标的距离小于两矩形横坐标上的长度和的1/2(同时纵坐标也要满足,画个图很明显),才有相交的面积,为了不失精度,都扩大2倍。


相交后新生成的矩形的坐标也是肯定直接确定的,画个图就可以理解。

代码:

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <list>

using namespace std;
int n, num[25], cnt, ans;
struct node
{
    int x[2],y[2],area; //坐标(x,y)左下角的下标为 0,右上角为 1,area为矩形面积
}rec[25];

bool Intersection(node a,node b)    //a,b矩形是否相交
{
    int zxa[2], zxb[2], lx[2], ly[2];
    lx[0] = a.x[1] - a.x[0], lx[1] = b.x[1] - b.x[0];//矩形a,b的宽(横坐标)
    ly[0] = a.y[1] - a.y[0], ly[1] = b.y[1] - b.y[0];//矩形a,b的长
    zxa[0] = a.x[1] + a.x[0], zxa[1] = a.y[1] + a.y[0];//重心所在的位置
    zxb[0] = b.x[1] + b.x[0], zxb[1] = b.y[1] + b.y[0];
    if(abs(zxa[0] - zxb[0]) < (lx[0] + lx[1]) && abs(zxa[1] - zxb[1]) < (ly[0] + ly[1]) )
        return true;
    return false;
}

void dfs(node r, int id, int k)
{
    node temp,t;
    if(id >= cnt) return ;
    for(int i = id+1;i < cnt;i++) {
        t = rec[num[i] ];
        if(Intersection(r,t)) {
            temp.x[0] = max(r.x[0], t.x[0]);//相交之后形成的重叠矩形的参数
            temp.y[0] = max(r.y[0], t.y[0]);
            temp.x[1] = min(r.x[1], t.x[1]);
            temp.y[1] = min(r.y[1], t.y[1]);
            temp.area = (temp.y[1] - temp.y[0]) * (temp.x[1] - temp.x[0]);
            if(k & 1) ans += temp.area;//奇加偶减
            else    ans -= temp.area;
            dfs(temp, i, k+1);
        }
    }
}

int main()
{
    int cas=1,m;
    while(~scanf("%d%d",&n,&m)) {
        if(!n && !m) break;
        for(int i = 0;i < n;i++) {
            for(int j = 0;j < 2;j++)
                scanf("%d%d",&rec[i].x[j],&rec[i].y[j]);
            rec[i].area = (rec[i].x[1] - rec[i].x[0]) * (rec[i].y[1] - rec[i].y[0]);
        }
        printf("Case %d:\n",cas++);
        for(int j = 0;j < m;j++) {
            scanf("%d",&cnt);
            ans = 0;
            for(int i = 0;i < cnt;i++) {
                scanf("%d",&num[i]);
                num[i] --;//矩形的编号从1开始。。。。。。
                ans += rec[num[i] ].area;
            }
            for(int i = 0;i < cnt;i++) {
                dfs(rec[num[i] ], i, 0);
            }
            printf("Query %d: %d\n",j+1,ans);
        }
        printf("\n");
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值