UVa11595 Crossing Streets EXTREME

题目链接

         UVa11595 - Crossing Streets EXTREME

题意

        平面上有 n(n≤35)条直线,各代表一条街道。街道相互交叉,形成一些路段(对应于几何上的线段)。你的任务是设计一条从A到B的路线,使得穿过路段的拥挤值之和尽量小。为了安全,你的路线不能直接穿过街道的交叉点,也不能沿着街道走,而只能从路段的中间过街。
        平面上还有c(c≤1000)座大楼。正常情况下,每条路段的拥挤值为1,但如果和一座大楼相邻(即可以从这座大楼出发,不经过其他路段或者交叉点到达这条路段),拥挤值需要加上该大楼的拥挤度。

分析

        综合了平面区域分割和加权最短路的繁琐题目。

        本题解决平面区域分割采用“卷包裹”算法比切割多边形算法更合适。根据本题的数据特点,加权最短路用Dijkstra比SPFA更合适一点。

        说一些细节:

        1、区域的边界[-M,M],M取值多少合适?不要被题目诱导直接取1000,这其实是错的,取1000000也不严谨,应该取2e9

        2、区域的边界值很大,伴随而来的套平面几何算法模板的一些与0比较相关的函数eps需要调整,分析下来应该取1e-31e-4

        3、对每条线段(所有直线加上4条边界裁剪后变成线段)计算它与其他线段的交点,需要去重索引起来,后面分割出多边形也只用点的索引保存,这能为后续处理带来便利。

        4、卷包裹分割出各个多边形后,怎么高效判断多边形相邻(有公共边)?每个多边形的边,要么只属于它(在外边界),要么还属于另外一个多边形,可以用map<pair<int, int>, int> mp来记录关联。比如某个多边形x有边pair(u, v),则包含此边的另外一个多边形y = mp[pair(v, u)]。

        5、根据多边形相邻关系及多边形包含的大楼建加权图,对每个查询用Dijkstra求解。

        给一份测试数据。

        更多繁琐细节,参见AC代码。

AC代码

#include <iostream>
#include <cmath>
#include <cstring>
#include <map>
#include <algorithm>
#include <queue>
using namespace std;

#define eps 1e-3
struct Point {
    double x, y;
    Point(double x = 0., double y = 0.): x(x), y(y) {}
};
typedef Point Vector;

Vector operator+ (const Vector& A, const Vector& B) {
    return Vector(A.x + B.x, A.y + B.y);
}

Vector operator- (const Vector& A, const Vector& B) {
    return Vector(A.x - B.x, A.y - B.y);
}

Vector operator* (const Vector& A, double p) {
    return Vector(A.x * p, A.y * p);
}

int dcmp(double x) {
    return abs(x) < eps ? 0 : (x < 0. ? -1 : 1);
}

bool operator== (const Point& a, const Point& b) {
    return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}

double Cross(const Vector& A, const Vector& B) {
    return A.x * B.y - A.y * B.x;
}

double Dot(const Vector& A, const Vector& B) {
    return A.x * B.x + A.y * B.y;
}

double LineInterp(const Point& P, const Vector& v, const Point& Q, const Vector& w) {
    Vector u = P - Q;
    return Cross(w, u) / Cross(v, w);
}

#define M 2.1e9
#define N 42
struct node {
    int h, i;
    bool operator< (const node& rhs) const {
        return h > rhs.h;
    }
};
int g[N*N>>1][N<<1], t[N*N>>1], u[N*N>>1][N], e[N*N>>1], w[N*N>>1], h[N*N>>1], m, n, c, q, kase = 0;
Point p[N*N>>1], s[N]; Vector v[N], d[N*N>>1][N<<1]; double l[N], f[N]; bool vis[N*N>>1][N<<1];

int addPoint(const Point& x) {
    for (int i=0; i<n; ++i) if (p[i] == x) return i;
    p[n] = x;
    return n++;
}

void dfs(int x, int i, int s) {
    vis[x][i] = true;
    if (x == s) u[m][0] = s, e[m] = 1;
    int y = g[x][i];
    if (y != s) {
        u[m][e[m]++] = y;
        double c = 1., f; int z = -1;
        for (int j=0; j<t[y]; ++j)
            if (!vis[y][j] && Cross(d[x][i], d[y][j]) > 0. && (f = Dot(d[x][i], d[y][j])) < c) c = f, z = j;
        if (z >= 0) dfs(y, z, s);
        for (int j=0; j<t[y]; ++j) if (!vis[y][j]) dfs(y, j, y);
    } else u[m][e[m]] = s, w[m++] = 0;
}

int find(const Point& t) {
    for (int i=0, wn; i<m; ++i) {
        for (int j=wn=0; j<e[i]; ++j) {
            int k = dcmp(Cross(p[u[i][j+1]]-p[u[i][j]], t-p[u[i][j]]));
            int d1 = dcmp(p[u[i][j]].y - t.y);
            int d2 = dcmp(p[u[i][j+1]].y - t.y);
            if (k > 0 && d1 <= 0 && d2 > 0) wn++;
            if (k < 0 && d2 <= 0 && d1 > 0) wn--;
        }
        if (wn) return i;
    }
    return m;
}

void addW() {
    Point t; int c; cin >> t.x >> t.y >> c; w[find(t)] += c;
}

int query() {
    Point s, u; cin >> s.x >> s.y >> u.x >> u.y;
    int x = find(s), y = find(u);
    if (x == y) return 0;
    memset(h, 10, sizeof(h)); h[x] = 0;
    priority_queue<node> q; q.push({0, x});
    while (!q.empty()) {
        node z = q.top(); q.pop(); int i = z.i;
        if (i == y) return h[y];
        if (z.h > h[i]) continue;
        for (int j=0; j<t[i]; ++j) {
            int k = g[i][j], v = h[i] + w[i] + w[k] + 1;
            if (h[k] > v) h[k] = v, q.push({h[k], k});
        }
    }
    return h[y];
}

void solve() {
    m = 4;
    while (n--) {
        int a, b, c; cin >> a >> b >> c;
        if (a == 0) {
            if (abs(c) >= M*abs(b)) continue;
            s[m] = {-M, c/(double)-b}; v[m] = {1., 0.}; l[m++] = 2.*M;
        } else if (b == 0) {
            if (abs(c) >= M*abs(a)) continue;
            s[m] = {c/(double)-a, -M}; v[m] = {0., 1.}; l[m++] = 2.*M;
        } else {
            double d = sqrt(a*a + b*b); s[m] = {-M, (a*M-c)/b}; v[m] = {abs(b)/d, b>0 ? -a/d : a/d};
            f[0] = 0.; f[1] = Dot(Point(M, -(a*M+c)/b) - s[m], v[m]); f[2] = Dot(Point((b*M-c)/a, -M) - s[m], v[m]);
            f[3] = Dot(Point(-(b*M+c)/a, M) - s[m], v[m]); sort(f, f+4);
            p[1] = s[m] + v[m]*f[1]; p[2] = s[m] + v[m]*f[2];
            if (!dcmp(f[1]-f[2]) || dcmp(max(max(abs(p[1].x), abs(p[1].y)), max(abs(p[2].x), abs(p[2].y))) - M) > 0)
                continue;
            s[m] = p[1]; l[m++] = f[2] - f[1];
        }
    }
    memset(t, n = 0, sizeof(t));
    for (int i=0; i<m; ++i) {
        f[0] = 0.; f[1] = l[i]; Vector r(-v[i].x, -v[i].y); int c = 2;
        for (int j=0; j<m; ++j) if (dcmp(Cross(v[i], v[j]))) {
            double t = LineInterp(s[i], v[i], s[j], v[j]);
            if (t > 0. && t < l[i]) f[c++] = t;
        }
        sort(f, f+c); c = unique(f, f+c) - f;
        for (int j=1, a = addPoint(s[i]+v[i]*f[0]), b; j<c; a=b, ++j) {
            if (dcmp(f[j]-f[j-1]) == 0) {
                b = a; continue;
            }
            g[a][t[a]] = b = addPoint(s[i]+v[i]*f[j]), g[b][t[b]] = a, d[a][t[a]++] = v[i], d[b][t[b]++] = r;
        }
    }
    memset(vis, 0, sizeof(vis)); dfs(0, 0, m = 0);
    map<pair<int, int>, int> b;
    for (int i=0; i<m; ++i) for (int j=0; j<e[i]; ++j) b[pair<int, int>(u[i][j], u[i][j+1])] = i;
    for (int i=0; i<m; ++i) {
        for (int j=t[i]=0; j<e[i]; ++j) {
            pair<int, int> p(u[i][j+1], u[i][j]);
            if (b.count(p)) g[i][t[i]++] = b[p];
        }
        sort(g[i], g[i]+t[i]); t[i] = unique(g[i], g[i]+t[i]) - g[i];
    }
    while (c--) addW();
    cout << "Case " << ++kase << ':' << endl;
    while (q--) cout << query() << endl;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    s[0] = s[3] = {-M, -M}; s[1] = {M, -M}; s[2] = {-M, M};
    v[0] = v[2] = {1., 0.}; v[1] = v[3] = {0., 1.}; l[0] = l[1] = l[2] = l[3] = 2.*M;
    while (cin >> n >> c >> q && n) solve();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/435253.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

土地利用数据分类过程教学/土地利用分类/遥感解译/土地利用获取来源介绍/地理数据获取

本篇主要介绍如何对影像数据进行分类解译&#xff0c;及过程教学&#xff0c;示例数据下载链接&#xff1a;数据下载链接 一、背景介绍 土地是人类赖以生存与发展的重要资源和物质保障&#xff0c;在“人口&#xff0d;资源&#xff0d;环境&#xff0d;发展&#x…

excel中去除公式,仅保留值

1.单个单元格去除公式 双击单元格&#xff0c;按F9. 2.批量去除公式 选中列然后复制&#xff0c;选择性粘贴&#xff0c;选值粘贴

C++之类型转换

C语言中的类型转换 在C语言中, 如果赋值运算符左右两侧类型不同, 或者形参与实参类型不匹配, 或者返回值类型与 接收返回值类型不一致时, 就需要发生类型转化, C语言中总共有两种形式的类型转换: 隐式类型转换和显式类型转换 1. 隐式类型转化是关联度很强, 意义相近的类型之间…

事务 失效的八种情况

在某些业务场景下&#xff0c;如果一个请求中&#xff0c;需要同时写入多张表的数据。为了保证操作的原子性&#xff08;要么同时成功&#xff0c;要么同时失败&#xff09;&#xff0c;避免数据不一致的情况&#xff0c;我们一般都会用到 spring 事务。 确实&#xff0c;sprin…

css使用伪元素绘制带三角箭头的提示框

效果图 代码实现 使用伪元素进行绘制&#xff1a; <div class"my-tip"></div> .my-tip{width: 128px;height: 100px;background: #FFFFFF;box-shadow: 0px 1px 10px 0px rgba(0,0,0,0.05), 0px 4px 5px 0px rgba(0,0,0,0.08), 0px 2px 4px -1px rgba(0…

【开源】SpringBoot框架开发网上药店系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 药品类型模块2.3 药品档案模块2.4 药品订单模块2.5 药品收藏模块2.6 药品资讯模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 角色表3.2.2 药品表3.2.3 药品订单表3.2.4 药品收藏表3.2.5 药品留言表…

Python 快速获取PDF文件的页数

有时在处理或打印一个PDF文档之前&#xff0c;你可能需要先知道该文档包含多少页。虽然我们可以使用Adobe Acrobat这样的工具来查看页数&#xff0c;但对于程序员来说&#xff0c;编写脚本来完成这项工作会更加高效。本文就介绍一个使用Python快速获取PDF文件页数的办法。 安装…

使用css结合js实现html文件中的双行混排

此前写过一个使用flex布局实现html文件中的双行混排&#xff0c;但是感觉效果不佳。经过几天思考&#xff0c;我认为双行混排的要点其实是两个&#xff1a; 1、正文和批注的文字大小不同&#xff1b; 2、正文和批注的行距相互配合进行设定。 正文和批注的文字大小及行距都可…

vue在线查看pdf文件

1.引入组件 npm install --save vue-pdf2、pdf组件页面模板 <template><div class"scrollBox" ><el-dialog :visible.sync"open" :top"1" width"50%" append-to-body><div slot"title"><el…

JUC总结

文章目录 java中线程的6种状态 静态变量、实例变量、局部变量的线程安全问题&#xff1a; 为什么会出现线程安全问题&#xff1a;在多个线程对共享资源读写操作&#xff0c;就会出现问题 synchronized 锁升级&#xff1a; sleep 和 wait 的区别 park和unpark 是unsafe中…

【视频转码】基于ZLMediakit的视频转码技术概述

一、概述 zlmediakit pro版本支持基于ffmpeg的转码能力&#xff0c;在开源版本强大功能的基础上&#xff0c;新增支持如下能力&#xff1a; 1、音视频间任意转码(包括h265/h264/opus/g711/aac等)。2、基于配置文件的转码&#xff0c;支持设置比特率&#xff0c;codec类型等参…

基于Spring Boot + Vue的信息化在线教学平台

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 目录 一、项目简介 二、开发技术与环…

个人商城系统开源(登录)

原文地址&#xff1a;个人商城系统开源&#xff08;登录&#xff09; - Pleasure的博客 下面是正文内容&#xff1a; 前言 由于近期实在没有什么话题可写和一些有趣的项目教程可以分享。所以我只能决定将我自己亲手编写的一个迷你迷你商城系统进行开源。 也就是放在我博客右边…

day06-网路编程

#include <myhead.h>int do_add(sqlite3 *ppDb) {int numb;char name[20];int age;int salary;printf("请输入要插入的信息:");scanf("%d %s %d %d", &numb, name, &age, &salary);char sql[128] "";sprintf(sql, "INSE…

SkyWalking 本地启动以及闪退问题

1. 下载包 Downloads | Apache SkyWalking SkyWalking APM包含OAP和UI Java Agent 就是Java 的探针 2. 运行 UI 默认端口是 8080&#xff0c; OAP 默认端口是 11800&#xff08;grpc&#xff09;12800&#xff08;http&#xff09; 如果占用可以修改配置文件 UI 项目的配…

手撕指针第一页

1. 理解内存和地址 1.1 内存 内存&#xff0c;顾名思义就是电脑用来存储数据的&#xff0c;当CPU&#xff08;中央处理器&#xff09;在工作时&#xff0c;不仅需要从内存中拿取数据也需要将数据放入内存当中&#xff0c;当把内存引入到现实当中&#xff0c;就像学校里面的宿…

如何恢复已删除的华为手机图片?5 种方式分享

不幸的现实是&#xff0c;华为的珍贵时刻有时会因为意外删除、软件故障或其他不可预见的情况而在眨眼之间消失。在这种情况下&#xff0c;寻求恢复已删除的图片成为个人迫切关心的问题。 本文旨在为用户提供如何从华为恢复已删除图片的实用解决方案。我们将探索五种可行的方法…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之RowSplit容器组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之RowSplit容器组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、RowSplit容器组件 将子组件横向布局&#xff0c;并在每个子组件之间插入一…

CentOS/Fedora/Ubuntu/Debian 系统 wget 命令

wget 是云服务器安装环境和面板常用下载命令。下载软件或从远程服务器下载备份到本地服务器&#xff0c;也可以使用 wget 把文件下载到云服务器上。 VPS wget 命令最常用使用方法如下&#xff1a; 安装 wget 一般来说 wget 命令是系统自带的&#xff0c;方面安装环境和面板&…

【Python】可变数据类型 不可变数据类型 || hash

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…