矩形切割题目

hdu 3634 City Planning

题意:

给出n个矩形的左下角左边(x1,y1)以及右上角的坐标(x2,y2)以及每个矩形的单位面积所具有的的价值,求如何安排矩形的放置顺序是的总价值最大,输出总价值。

思路:
首先,这些矩形会有重叠的部分,重叠的部分肯定取val值最大的,所以我们首先按照每个矩形的val值排序,然后然后利用当前的矩形去切割前边切割出来的矩形,重叠部分肯定取当前的矩形的val计算,最后求切割出来的矩形的总价值即可。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 30007
#define N 50007

using namespace std;

const int inf = 100000007;
const int mod = 1000000007;

struct node
{
    int p1[2],p2[2];//左下角的点,右上角的点
    int val;
}a[N],b[22];

int cmp(node a,node b)
{
    return a.val < b.val;
}
//判断是否相交
bool intersect(node a,node b)
{
    for (int i = 0; i < 2; ++i)
    {
        if (a.p2[i] <= b.p1[i] || a.p1[i] >= b.p2[i]) return false;
    }
    return true;
}
int tot;
//用ta矩形切割tb矩形
void cut(node ta,node tb)
{
    for (int i = 0; i < 2; ++i)
    {
        int k1 = max(ta.p1[i],tb.p1[i]);
        int k2 = min(ta.p2[i],tb.p2[i]);

        if (tb.p1[i] < k1)
        {
            a[++tot] = tb;
            a[tot].p2[i] = k1;
        }
        if (tb.p2[i] > k2)
        {
            a[++tot] = tb;
            a[tot].p1[i] = k2;
        }
        tb.p1[i] = k1; tb.p2[i] = k2;
    }
}
int main()
{
    int T,i,j;
    int cas = 1;
    int n;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        for (i = 1; i <= n; ++i)
        {
            scanf("%d%d%d%d%d",&b[i].p1[0],&b[i].p1[1],&b[i].p2[0],&b[i].p2[1],&b[i].val);
        }
        sort(b + 1, b + 1 + n,cmp);
        tot = 0;
        for (i = 1; i <= n; ++i)
        {
            for (j = tot; j >= 1; --j)
            {
                if (intersect(b[i],a[j]))
                {
                    cut(b[i],a[j]);
                    a[j] = a[tot--];//覆盖掉原来切割后的矩形
                }
            }
            //将最后的矩形放进来
            a[++tot] = b[i];
        }
        ll sum = 0;
        for (i = 1; i <= tot; ++i)
        {
//            printf("%d %d\n",i,a[i].val);
            sum += (ll)a[i].val*(a[i].p2[0] - a[i].p1[0])*(a[i].p2[1] - a[i].p1[1]);
        }
        printf("Case %d: %I64d\n",cas++,sum);
    }
    return 0;
}

 

 pku 2528 Mayor's posters

经典的贴海报的那个离散化+线段树的题目, 不过这里可以用矩形切割(这里是线段切割)来做,这里到了(10^8*T)不过可能后台数据比较弱,竟然也能过。

根据当前线段切割之前切出来的线段,然后求解即可。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 30007
#define N 1000007

using namespace std;

const int inf = 100000007;
const int mod = 1000000007;

struct node
{
    int p1,p2;
    int col;
}a,b[N];
bool vt[10007];
int tot;

bool intersect(node a,node b)
{
    if (a.p2 < b.p1 || a.p1 > b.p2) return false;
    return true;
}
void cut(node ta,node tb)
{
    int k1 = max(ta.p1,tb.p1);
    int k2 = min(ta.p2,tb.p2);
    if (tb.p1 < k1)
    {
        b[++tot] = tb;
        b[tot].p2 = k1 - 1;
    }
    if (tb.p2 > k2)
    {
        b[++tot] = tb;
        b[tot].p1 = k2 + 1;
    }
}
int cmp(node a,node b)
{
    return a.col < b.col;
}
int main()
{
    int T,i,j;
    int n;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        tot = 0;
        for (i = 1; i <= n; ++i)
        {
            scanf("%d%d",&a.p1,&a.p2);
            a.col = i;
            for (j = tot; j >= 1; --j)
            {
                if (intersect(a,b[j]))
                {
                    cut(a,b[j]);
                    b[j] = b[tot--];
                }
            }
            b[++tot] = a;
        }
//        sort(b + 1,b + 1 + tot,cmp);
        int ans = 0;
        CL(vt,false);
        for (i = 1; i <= tot; ++i)
        {
            if (!vt[b[i].col])
            {
                ans++; vt[b[i].col] = true;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

 pku 1151 Atlantis

 同样是经典的线段树求矩形面积并的题目,这里用矩形切割的话,代码量很短。

同时注意精度的处理,同时还要理解一个问题,当我们给出左上角和右下角的坐标是我们是按照左上角为(0,0)建立的坐标系,如果给出左下角和右上角的时候是按照左下角为(0,0)建立的图,所以我们的for循环处理判断相交是都是对的。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 30007
#define N 107

using namespace std;

const int inf = 100000007;
const int mod = 1000000007;
const double eps = 1e-6;

struct node
{
    double p1[2],p2[2];
}a,b[N*N];
int tot;

int dblcmp(double x)
{
    if (x > eps) return 1;
    else if (x < -eps) return -1;
    else return 0;
}
bool intersect(node ta,node tb)
{
    for (int i = 0; i < 2; ++i)
    {
        if (dblcmp(ta.p2[i] - tb.p1[i]) <= 0 || dblcmp(ta.p1[i] - tb.p2[i]) >= 0) return false;
    }
    return true;
}
void cut(node ta,node tb)
{
    for (int i = 0; i < 2; ++i)
    {
        int k1 = max(ta.p1[i],tb.p1[i]);
        int k2 = min(ta.p2[i],tb.p2[i]);

        if (dblcmp(tb.p1[i] - k1) < 0)
        {
            b[++tot] = tb;
            b[tot].p2[i] = k1;
        }
        if (dblcmp(tb.p2[i] - k2) > 0)
        {
            b[++tot] = tb;
            b[tot].p1[i] = k2;
        }
        tb.p1[i] = k1;
        tb.p2[i] = k2;
    }
}
int main()
{
    int n,i,j;
    int cas = 1;
    while (~scanf("%d",&n))
    {
        if (!n) break;
        tot = 0;
        for (i = 1; i <= n; ++i)
        {
            scanf("%lf%lf%lf%lf",&a.p1[0],&a.p1[1],&a.p2[0],&a.p2[1]);
            for (j = tot; j >= 1; --j)
            {
                if (intersect(a,b[j]))
                {
                    cut(a,b[j]);
                    b[j] = b[tot--];
                }
            }
            b[++tot] = a;
        }
        double sum = 0;
        for (i = 1; i <= tot; ++i)
        {
            sum += (b[i].p2[0] - b[i].p1[0])*(b[i].p2[1] - b[i].p1[1]);
        }
        printf("Test case #%d\n",cas++);
        printf("Total explored area: %.2lf\n\n",sum);
    }
    return 0;
}

 

pku 3277 City Horizon

题意:

给出n个矩形的最下边一条边在x轴上的坐标以及该矩形的高度,求n个矩形面积的并。

思路:

n很大,觉得矩形切割肯定会超时,怎么会分到矩形切割呢。于是就将给出的矩形转化成左下角坐标和右上角坐标,求解。结果真的tle了。后来看了看解题报告, 原来按照高度排序转化成线段切割就好了。不过感觉数据量依然很大,理论上应该是会超时的可是这里可能是后台数据弱吧。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 30007
#define N 4000007

using namespace std;

const int inf = 100000007;
const int mod = 1000000007;
const double eps = 1e-6;


struct node
{
    ll p1,p2;
    ll h;
}a[N],b[N];

int tot;

int cmp(node a,node b)
{
    return a.h < b.h;
}
bool intersect(node ta,node tb)
{

    if (ta.p2 <= tb.p1 || ta.p1 >= tb.p2) return false;

    return true;
}
void cut(node ta,node tb)
{

    ll k1 = max(ta.p1,tb.p1);
    ll k2 = min(ta.p2,tb.p2);

    if (tb.p1 < k1)
    {
        b[++tot] = tb;
        b[tot].p2 = k1;
    }
    if (tb.p2 > k2)
    {
        b[++tot] = tb;
        b[tot].p1 = k2;
    }
}
int main()
{
//    Read();
    int i,j,n;
    scanf("%d",&n);
    for (i = 1; i <= n; ++i)
    {
        scanf("%I64d%I64d%I64d",&a[i].p1,&a[i].p2,&a[i].h);
    }
    sort(a + 1,a + 1 + n,cmp);

    tot = 0;
    for (i = 1; i <= n; ++i)
    {
        for (j = tot; j >= 1; --j)
        {
            if (intersect(a[i],b[j]))
            {
                cut(a[i],b[j]);
                b[j] = b[tot--];
            }
        }
        b[++tot] = a[i];
    }
    ll sum = 0;
    for (i = 1; i <= tot; ++i)
    {
        sum += (b[i].p2 - b[i].p1)*b[i].h;
    }
    cout<<sum<<endl;
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值