zoukankan      html  css  js  c++  java
  • POJ 1151 Atlantis

    POJ_1151

        这个题目是我第一次接触离散化的东西,看了黑书相关的部分后便按自己的理解设计了一个算法:

        首先将x-y平面看成被矩形的四个边所在的直线切成了若干块,然后把每一块看成1个点,之后扫描一遍所有矩形,把这些矩形覆盖的点标记一下,最后再计算一下所有标记的点的面积即可。

        这样做排序x坐标是O(nlogn)的复杂度,排序y坐标是O(nlogn),由于x和y轴最多被切2*n刀,所以最后得到的点的数量是n^2数量级的,这样标记矩形覆盖的点就是O(n^3)的复杂度,最后扫描的时候是O(n^2)的复杂度,提交之后TLE了。

        之所以TLE是因为O(n^3)的复杂度过高了,我们必须降低这一部分的复杂度。对比最后扫描的复杂度,油然而生一个想法,能不能不标记矩形覆盖的点,而直接在最后扫描的时候就计算出覆盖的面积呢?如果这样可行的话就有希望降到O(n^2)的复杂度。

        细想一下是可以的,我们在最后扫描的时候会先枚举x,然后y由小向大计算,如果矩形是对y1有序的话,我们就可以保证扫描一遍矩形就能计算出当前这个x范围上,有多少面积是被覆盖的。具体计算的时候用up和down表示一个连续的被覆盖部分的上端和下端,一开始置为-1,然后逐一扫描排序后的矩形,如果当前矩形的y1比up大,那么就说明不会和之前覆盖的部分有重叠了,于是就可以将前面覆盖部分的面积计算出来累加到结果中去了,如果当前矩形的y1不比up大,但y2比up大,就说明连续覆盖的面积又向上延伸了,更新一下up即可。

        后来用O(n^2)的算法交的时候RE了一次,才发现我数组开小了,所以之前O(n^3)的算法为什么超时也就不清楚是因为数组开小了还是因为算法复杂度太高了,因为O(n^3)是10^6左右,理论上也应该可以AC的。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define INF 100010
    #define MAXD 220
    #define zero 1e-8
    struct square
    {
    double x1, y1, x2, y2;
    }s[MAXD];
    int X, N;
    double left[MAXD], right[MAXD], tx[MAXD];
    int cmp1(const void *_p, const void *_q)
    {
    square *p = (square *)_p, *q = (square *)_q;
    return p->y1 < q->y1 ? -1 : 1;
    }
    int cmp2(const void *_p, const void *_q)
    {
    double *p = (double *)_p, *q = (double *)_q;
    return *p < *q ? -1 : 1;
    }
    double fabs(double x)
    {
    return x < 0 ? -x : x;
    }
    int dcmp(double x)
    {
    return fabs(x) < zero ? 0 : (x < 0 ? -1 : 1);
    }
    void init()
    {
    int i, j, k = 2;
    tx[0] = -1, tx[1] = INF;
    for(i = 0; i < X; i ++)
    {
    scanf("%lf%lf%lf%lf", &s[i].x1, &s[i].y1, &s[i].x2, &s[i].y2);
    tx[k ++] = s[i].x1;
    tx[k ++] = s[i].x2;
    }
    qsort(s, X, sizeof(s[0]), cmp1);
    qsort(tx, k, sizeof(tx[0]), cmp2);
    N = 0;
    for(i = 1; i < k; i ++)
    if(dcmp(tx[i] - tx[i - 1]) != 0)
    {
    left[N] = tx[i - 1], right[N] = tx[i];
    ++ N;
    }
    }
    void solve()
    {
    int i, j, k;
    double ans = 0, down, up;
    for(i = 0; i < N; i ++)
    {
    down = up = -1;
    for(j = 0; j < X; j ++)
    if(dcmp(left[i] - s[j].x1) >= 0 && dcmp(right[i] - s[j].x2) <= 0)
    {
    if(dcmp(s[j].y1 - up) > 0)
    {
    ans += (right[i] - left[i]) * (up - down);
    down = s[j].y1, up = s[j].y2;
    }
    else if(dcmp(s[j].y2 - up) > 0)
    up = s[j].y2;
    }
    ans += (right[i] - left[i]) * (up - down);
    }
    printf("Total explored area: %.2lf\n", ans);
    }
    int main()
    {
    int t = 0;
    for(;;)
    {
    scanf("%d", &X);
    if(!X)
    break;
    init();
    printf("Test case #%d\n", ++ t);
    solve();
    printf("\n");
    }
    return 0;
    }


  • 相关阅读:
    10 种保护 Spring Boot 应用的绝佳方法
    Redis 如何分析慢查询操作?
    Spring Boot 主类及目录结构介绍
    Redis 再牛逼,也得设置密码!!
    Spring Data Redis 详解及实战一文搞定
    Spring Boot Redis Cluster 实战干货
    超详细的 Redis Cluster 官方集群搭建指南
    Redis Linux 安装运行实战全记录
    hdu 4790 Just Random (思路+分类计算+数学)
    poj 1328 Radar Installation(贪心)
  • 原文地址:https://www.cnblogs.com/staginner/p/2359396.html
Copyright © 2011-2022 走看看