• 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, int> mp来记录关联。比如某个多边形x有边pair(u, v),则包含此边的另外一个多边形y = mp[pair(v, u)]。

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

            给一份测试数据

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

    AC代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. using namespace std;
    8. #define eps 1e-3
    9. struct Point {
    10. double x, y;
    11. Point(double x = 0., double y = 0.): x(x), y(y) {}
    12. };
    13. typedef Point Vector;
    14. Vector operator+ (const Vector& A, const Vector& B) {
    15. return Vector(A.x + B.x, A.y + B.y);
    16. }
    17. Vector operator- (const Vector& A, const Vector& B) {
    18. return Vector(A.x - B.x, A.y - B.y);
    19. }
    20. Vector operator* (const Vector& A, double p) {
    21. return Vector(A.x * p, A.y * p);
    22. }
    23. int dcmp(double x) {
    24. return abs(x) < eps ? 0 : (x < 0. ? -1 : 1);
    25. }
    26. bool operator== (const Point& a, const Point& b) {
    27. return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
    28. }
    29. double Cross(const Vector& A, const Vector& B) {
    30. return A.x * B.y - A.y * B.x;
    31. }
    32. double Dot(const Vector& A, const Vector& B) {
    33. return A.x * B.x + A.y * B.y;
    34. }
    35. double LineInterp(const Point& P, const Vector& v, const Point& Q, const Vector& w) {
    36. Vector u = P - Q;
    37. return Cross(w, u) / Cross(v, w);
    38. }
    39. #define M 2.1e9
    40. #define N 42
    41. struct node {
    42. int h, i;
    43. bool operator< (const node& rhs) const {
    44. return h > rhs.h;
    45. }
    46. };
    47. 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;
    48. 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];
    49. int addPoint(const Point& x) {
    50. for (int i=0; iif (p[i] == x) return i;
    51. p[n] = x;
    52. return n++;
    53. }
    54. void dfs(int x, int i, int s) {
    55. vis[x][i] = true;
    56. if (x == s) u[m][0] = s, e[m] = 1;
    57. int y = g[x][i];
    58. if (y != s) {
    59. u[m][e[m]++] = y;
    60. double c = 1., f; int z = -1;
    61. for (int j=0; j
    62. 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;
    63. if (z >= 0) dfs(y, z, s);
    64. for (int j=0; jif (!vis[y][j]) dfs(y, j, y);
    65. } else u[m][e[m]] = s, w[m++] = 0;
    66. }
    67. int find(const Point& t) {
    68. for (int i=0, wn; i
    69. for (int j=wn=0; j
    70. int k = dcmp(Cross(p[u[i][j+1]]-p[u[i][j]], t-p[u[i][j]]));
    71. int d1 = dcmp(p[u[i][j]].y - t.y);
    72. int d2 = dcmp(p[u[i][j+1]].y - t.y);
    73. if (k > 0 && d1 <= 0 && d2 > 0) wn++;
    74. if (k < 0 && d2 <= 0 && d1 > 0) wn--;
    75. }
    76. if (wn) return i;
    77. }
    78. return m;
    79. }
    80. void addW() {
    81. Point t; int c; cin >> t.x >> t.y >> c; w[find(t)] += c;
    82. }
    83. int query() {
    84. Point s, u; cin >> s.x >> s.y >> u.x >> u.y;
    85. int x = find(s), y = find(u);
    86. if (x == y) return 0;
    87. memset(h, 10, sizeof(h)); h[x] = 0;
    88. priority_queue q; q.push({0, x});
    89. while (!q.empty()) {
    90. node z = q.top(); q.pop(); int i = z.i;
    91. if (i == y) return h[y];
    92. if (z.h > h[i]) continue;
    93. for (int j=0; j
    94. int k = g[i][j], v = h[i] + w[i] + w[k] + 1;
    95. if (h[k] > v) h[k] = v, q.push({h[k], k});
    96. }
    97. }
    98. return h[y];
    99. }
    100. void solve() {
    101. m = 4;
    102. while (n--) {
    103. int a, b, c; cin >> a >> b >> c;
    104. if (a == 0) {
    105. if (abs(c) >= M*abs(b)) continue;
    106. s[m] = {-M, c/(double)-b}; v[m] = {1., 0.}; l[m++] = 2.*M;
    107. } else if (b == 0) {
    108. if (abs(c) >= M*abs(a)) continue;
    109. s[m] = {c/(double)-a, -M}; v[m] = {0., 1.}; l[m++] = 2.*M;
    110. } else {
    111. 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};
    112. 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]);
    113. f[3] = Dot(Point(-(b*M+c)/a, M) - s[m], v[m]); sort(f, f+4);
    114. p[1] = s[m] + v[m]*f[1]; p[2] = s[m] + v[m]*f[2];
    115. 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)
    116. continue;
    117. s[m] = p[1]; l[m++] = f[2] - f[1];
    118. }
    119. }
    120. memset(t, n = 0, sizeof(t));
    121. for (int i=0; i
    122. f[0] = 0.; f[1] = l[i]; Vector r(-v[i].x, -v[i].y); int c = 2;
    123. for (int j=0; jif (dcmp(Cross(v[i], v[j]))) {
    124. double t = LineInterp(s[i], v[i], s[j], v[j]);
    125. if (t > 0. && t < l[i]) f[c++] = t;
    126. }
    127. sort(f, f+c); c = unique(f, f+c) - f;
    128. for (int j=1, a = addPoint(s[i]+v[i]*f[0]), b; j
    129. if (dcmp(f[j]-f[j-1]) == 0) {
    130. b = a; continue;
    131. }
    132. 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;
    133. }
    134. }
    135. memset(vis, 0, sizeof(vis)); dfs(0, 0, m = 0);
    136. mapint, int>, int> b;
    137. for (int i=0; ifor (int j=0; jpair<int, int>(u[i][j], u[i][j+1])] = i;
    138. for (int i=0; i
    139. for (int j=t[i]=0; j
    140. pair<int, int> p(u[i][j+1], u[i][j]);
    141. if (b.count(p)) g[i][t[i]++] = b[p];
    142. }
    143. sort(g[i], g[i]+t[i]); t[i] = unique(g[i], g[i]+t[i]) - g[i];
    144. }
    145. while (c--) addW();
    146. cout << "Case " << ++kase << ':' << endl;
    147. while (q--) cout << query() << endl;
    148. }
    149. int main() {
    150. ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    151. s[0] = s[3] = {-M, -M}; s[1] = {M, -M}; s[2] = {-M, M};
    152. v[0] = v[2] = {1., 0.}; v[1] = v[3] = {0., 1.}; l[0] = l[1] = l[2] = l[3] = 2.*M;
    153. while (cin >> n >> c >> q && n) solve();
    154. return 0;
    155. }

  • 相关阅读:
    知识文库杂志知识文库杂志社知识文库编辑部2022年第14期目录
    2021年12月 Python(二级)真题解析#中国电子学会#全国青少年软件编程等级考试
    Bash基本功能—多命令顺序执行与管道符
    flutter升级AS和gradle后编译出错(No signature of method: build_gbqp6.android())错误
    二叉树理论基础篇
    [docker] -- 初识docker
    为什么电商创业者2022年都在做抖音小店无货源?揭开抖店无货源玩法
    对于AIGC(人工智能)我们应该如何看待
    JavaEE平台技术——预备知识(Web、Sevlet、Tomcat)
    C语言小项目——通讯录的存储系统(静态版,动态版,文件版)
  • 原文地址:https://blog.csdn.net/hlhgzx/article/details/136522227