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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++: 引用能否替代指针? 详解引用与指针的区别.

文章目录 前言1. 引用和指针的最大区别:引用不能改变指向2. 引用和指针在底层上面是一样的3. 引用和指针在sizeof面前大小不同4. 有多级指针,没有多级引用5.引用是引用的实体,指针会向后偏移同一个类型的大小 总结 前言 新来的小伙伴如果不知道引用是什么?可以看我的上一篇文…

AI新工具(20240312) Midjourney官方发布角色一致性功能;免费且开源的简历制作工具;精确克隆语调、控制声音风格

1: Midjourney角色一致性功能 使人物画像在多方面高度一致成为可能。 Midjourney的角色一致性功能的使用方法如下&#xff1a; ⭐在你的输入指令后面加上 --cref URL&#xff0c;其中URL是你选择的角色图像的链接。 ⭐你可以通过 --cw 参数来调整参照的强度&#xff0c;范围…

spring boot 使用 webservice

spring boot 使用 webservice 使用 java 自带的 jax-ws 依赖 如果是jdk1.8,不需要引入任何依赖&#xff0c;如果大于1.8 <dependency><groupId>javax.jws</groupId><artifactId>javax.jws-api</artifactId><version>1.1</version&g…

【Linux】文件缓冲区|理解文件系统

目录 预备知识 观察现象 第一&#xff1a;携带\n&#xff0c;不使用fork()&#xff0c;打印到显示器 第二&#xff1a;携带\n&#xff0c;使用fork()&#xff0c;打印到显示器 第三&#xff1a;携带\n&#xff0c;使用fork()&#xff0c;打印到文件里 第四&#xff1a;不携…

案例分析篇03:一篇文章搞定软考设计模式考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…

IPSec NAT穿越原理

一、IPSec VPN在NAT场景中存在的问题 当某些组网中&#xff0c;有的分支连动态的公网IP地址也没有&#xff0c;只能由网络中的NAT设备进行地址转换&#xff0c;才能访问互联网&#xff0c;然而IPsec是用来保护报文不被修改的&#xff0c;而NAT需要修改报文的IP地址&#xff0c…

十大排序算法(冒泡排序、插入排序、选择排序、希尔排序、堆排序、快排、归并排序、桶排序、计数排序、基数排序)

目录 一、冒泡排序&#xff1a; 二、插入排序&#xff1a; 三、选择排序&#xff1a; 四、希尔排序&#xff1a; 五、堆排序&#xff1a; 六、快速排序&#xff1a; 6.1挖坑法&#xff1a; 6.2左右指针法 6.3前后指针法&#xff1a; 七、归并排序&#xff1a; 八、桶…

力扣hot100:240.搜索二维矩阵II(脑子)

吉大21级算法分析与设计的一道大题&#xff0c;由于每一行都是排好序的直接逐行二分 可以达到&#xff1a;O(mlogn)。但是这里追求更广的思路可以使用其他方法。 矩阵四分&#xff1a; 在矩阵中用中心点比较&#xff0c;如果target大于中心点的值&#xff0c;则由于升序排列&am…

vue学习笔记23-组件事件⭐

组件事件 在组件的模板表达式中&#xff0c;可以直接使用$emit方法触发自定义事件&#xff1b;触发自定义事件的目的是组件之间传递数据 好好好今天又碰到问题了&#xff0c;来吧来吧 测试发现其他项目都可以 正常的run ,就它不行 搜索发现新建项目并进入以后&#xff0c;用指…

C语言--- 指针运算笔试题详解

目录 题目1&#xff1a; 题目2&#xff1a; 题目3&#xff1a; 题目4&#xff1a; 题目5&#xff1a; 题目6&#xff1a; 题目7&#xff1a; 题目1&#xff1a; #include <stdio.h> int main() {int a[5] { 1, 2, 3, 4, 5 };int *ptr (int *)(&a 1);print…

新书推荐|职业教育赛教一体化课程改革系列教材之spark大数据分析

由武汉唯众智创科技有限公司统一规划并参与编写的“职业教育赛教一体化课程改革系列教材”-《spark大数据分析》正式出版上线&#xff0c;(其它八本为《云计算技术与应用》《大数据技术与应用Ⅰ》《网络综合布线》《物联网.NET开发》《物联网嵌入式开发》《物联网移动应用开发》…

Cloud-Eureka服务治理-Ribbon负载均衡

构建Cloud父工程 父工程只做依赖版本管理 不引入依赖 pom.xml <packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEA…

Request和Response对象

Request和Response都是Servlet的service方法的参数&#xff0c;Request负责获取请求数据&#xff0c;而Response负责设置相应数据~ 一.Request 1.继承体系 Tomcat负责解析数据&#xff0c;因此由Tomcat来提供实现类~ 2.获取请求数据 请求行 请求头 请求体 需要注意的是只有…

day1-C++

1>提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数要求使用C风格字符串完成。 代码&#xff1a; #include <iostream> #include <string.h> using namespace std;int main() {string str ;int low 0, …

selenium高级应用

常见控件应用 复杂的控件操作1.操作Ajax选项2.滑动滑块操作 WebDriver的特殊操作元素class值包含空格property、attribute、text的区别定位动态id 截图功能页面截图页面截图&#xff0c;返回截图的二进制数据页面截图&#xff0c;返回base64的字符串截取指定元素。先定位元素&a…

【CSP试题回顾】201912-2-回收站选址

CSP-201912-2-回收站选址 关键点&#xff1a;时间复杂度 1.暴力枚举方法&#xff1a; 暴力枚举方法会遍历二维空间中的每一个点&#xff0c;对于每一个点&#xff0c;检查它的四个直接邻居是否都是垃圾点&#xff0c;然后对于每一个满足条件的点&#xff0c;再检查它的四个对…

SpringCloud Ribbon 负载均衡服务调用

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第三篇&#xff0c;即介绍 Ribbon 负载均衡服务调用 二、概述 2.1 Ribbon 是什么 Spring Cloud Ribbon…

计算机网络—以太网接口和链路配置

目录 1.拓扑图 2.以太网交换机基础配置 3.配置手动模式的链路聚合 4.配置静态 LACP 模式的链路聚合 5.配置文件 1.拓扑图 2.以太网交换机基础配置 华为交换机接口默认开启了自协商功能&#xff0c;需要手动配置S1与 S2上G0/0/9和G0/0/10接口的速率。 首先修改交换机的设…

某准网招聘接口逆向之WebPack扣取

​​​​​逆向网址 aHR0cHM6Ly93d3cua2Fuemh1bi5jb20v 逆向链接 aHR0cHM6Ly93d3cua2Fuemh1bi5jb20vc2VhcmNoP3BhZ2VOdW09MSZxdWVyeT1weXRob24mdHlwZT01 逆向接口 aHR0cHM6Ly93d3cua2Fuemh1bi5jb20vYXBpX3RvL3NlYXJjaC9qb2IuanNvbg 逆向过程 请求方式&#xff1a;GET 参数构成…

分享个好用的GPT网站

目录 一、背景 二、功能描述 1、写代码 2、联网查询 3、AI绘图 一、背景 我现在的开发工作都依靠ChatGPT&#xff0c;效率提升了好几倍。这样一来&#xff0c;我有更多时间来摸鱼&#xff0c;真是嘎嘎香~ ⭐⭐⭐点击直达 ⭐⭐⭐ 二、功能描述 1、写代码 import java.ut…