GYM - 101147 B.Street
题意:
大矩形代表市场,大矩形当中有很多小矩形样式的伞。这些小矩形都贴着大矩形的左边或者右边且互不相交。小矩形以外的地方都是阳光。求经过大矩形时在阳光下的最短时间。
题解:
最短路的做法。起点和终点与每个矩形之间连边,每两个矩形之间也连边。
矩形之间两边有三种情况:1.两个矩形在同一边(k值相等)或两个矩形的宽度和大于(不能大于等于)大矩形的宽度
2.两个矩形的长度区间不相交(a[i].h+a[i].d<a[j].d||a[j].h+a[j].d<a[i].d)
3.长度区间相交
#include <bits/stdc++.h> using namespace std; typedef long long ll; int t, n, vis[105]; double L, U; double diss[105]; struct rec { double h, w, d; int k; }r[105]; struct node { int to; double val; node(int a, double b) { to = a; val = b; } }; vector<node> g[105]; double distance(double x1, double y1, double x2, double y2) { return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); } void add_edge(int u, int v, double val) { g[u].push_back(node(v, val)); g[v].push_back(node(u, val)); } void unite(int u, int v) { double dis; if(r[u].k==r[v].k || r[u].w+r[v].w > U) dis = max(r[u].d-r[v].d-r[v].h, r[v].d-r[u].d-r[u].h); else { if(r[u].d > r[v].d+r[v].h) dis = distance(r[u].w, r[u].d, U-r[v].w, r[v].d+r[v].h); else if(r[v].d > r[u].d+r[u].h) dis = distance(r[v].w, r[v].d, U-r[u].w, r[u].d+r[u].h); else dis = U-r[u].w-r[v].w; } add_edge(u, v, dis); } void spfa(int s) { queue<int> q; q.push(s); memset(vis, 0, sizeof(vis)); vis[s] = 1; while(!q.empty()) { int v = q.front(); q.pop(); vis[v] = 0; int len = g[v].size(); for(int i = 0; i < len; i++) { if(g[v][i].val+diss[v] < diss[g[v][i].to]) { diss[g[v][i].to] = g[v][i].val+diss[v]; if(!vis[g[v][i].to]) { q.push(g[v][i].to); vis[g[v][i].to] = 1; } } } } } int main() { freopen("street.in","r",stdin); scanf("%d", &t); while(t--) { scanf("%d%lf%lf", &n, &L, &U); for(int i = 0; i <= n+1; i++) { g[i].clear(); if(i) diss[i] = 1e15; } for(int i = 1; i <= n; i++) scanf("%lf%lf%lf%d", &r[i].h, &r[i].w, &r[i].d, &r[i].k); for(int i = 1; i <= n; i++) { add_edge(0, i, r[i].d); add_edge(n+1, i, L-r[i].d-r[i].h); } for(int i = 1; i < n; i++) for(int j = i+1; j <= n; j++) unite(i, j); spfa(0); printf("%.6lf\n", diss[n+1]); } }