AOJ 2099 Walk under a Scorching Sun
問題
凸多角柱で表されるn個の建物がある
太陽がx軸から反時計回りにθの角度の方向で、高さφの角度にある。
m本の道があって、それぞれの道は線分である。
スタートの点(sx, sy)からゴールの点(gx, gy)へ、道を通って行く。
道のうち太陽の当たっている部分の長さを最小化したい。
道のうち太陽の当たっている部分の長さの最小値を求めよ。
太陽光線は平行であるとしてよい。
制約条件
n≦15
m≦15
各多角形の頂点は10個以下
方針
道同士の交点を最初に全部求める。
道の間に点がある道は分割する。
道ごとに太陽の当たる部分の長さを求める。
これは、建物の一辺が作る影が平行四辺形になることから、
適当に交点を求めたりすれば求まる。
自分は影の作る平行四辺形による、道路の切断を考え、
そこから区間でカバーされてる部分を求める感じでやった。
道ごとのコストがわかったら、グラフを作ってダイクストラする。
ソースコード
const double PI = acos(-1.0); int n, m; double phi, theta, len[200], h[100]; vector<G> bs; vector<L> ss; vector<P> ps; vector<vector<pair<int, double> > > e; int main() { while(cin >> n >> m, n){ bs.clear(); ss.clear(); ps.clear(); e.clear(); rep(i, n){ int k, x, y; G g; cin >> k >> h[i]; rep(j, k) cin >> x >> y, g.pb(P(x, y)); bs.pb(g); } rep(i, m){ int x, y, X, Y; cin >> x >> y >> X >> Y; ss.pb(L(P(x, y), P(X, Y))); } cin >> theta >> phi; theta *= PI / 180; theta += PI; phi *= PI / 180; int sx, sy, tx, ty; cin >> sx >> sy >> tx >> ty; rep(i, m) ps.pb(ss[i][0]), ps.pb(ss[i][1]); rep(i, m) rep(j, i) if(intersectSS(ss[i], ss[j])){ rep(k, 2) rep(l, 2) if(ss[i][k] == ss[j][l]) goto SKIP; ps.pb(crosspoint(ss[i], ss[j])); SKIP:; } ps.pb(P(sx, sy)); ps.pb(P(tx, ty)); sort(all(ps)); rep(i, m){ rep(j, ps.size()){ if(abs(ss[i][0] - ps[j]) < EPS || abs(ss[i][1] - ps[j]) < EPS) continue; if(!intersectSP(ss[i], ps[j])) continue; ss.pb(L(ps[j], ss[i][1])); ss[i][1] = ps[j]; m++; } } rep(i, m){ map<double, int> iv; double d = abs(ss[i][0] - ss[i][1]); rep(j, n){ P x = h[j] * P(cos(theta), sin(theta)) / tan(phi); rep(k, bs[j].size()){ int nk = (k + 1) % bs[j].size(); G g, s; g.pb(bs[j][nk]); g.pb(bs[j][nk] + x); g.pb(bs[j][k] + x); g.pb(bs[j][k]); if(ccw(g[0], g[1], g[2]) != 1) reverse(all(g)); s.pb(ss[i][0]); s.pb(ss[i][1]); rep(l, 4) s = convex_cut(s, L(g[l], g[(l + 1) % 4])); if(s.empty()) continue; double a = abs(s[0] - ss[i][0]) / d, b = abs(s[1] - ss[i][0]) / d; if(a > b) swap(a, b); iv[a]++; iv[b + EPS]--; } } int cnt = 0; double prev = 0, sum = 0; iv[1] = 0; each(it, iv){ if(cnt == 0) sum += it->first - prev; prev = it->first; cnt += it->second; } len[i] = sum * d; } e.resize(ps.size()); map<P, int> id; rep(i, ps.size()) id[ps[i]] = i; rep(i, m){ int a = id[ss[i][0]], b = id[ss[i][1]]; e[a].pb(mp(b, len[i])); e[b].pb(mp(a, len[i])); } priority_queue<pair<double, int> > q; set<int> v; q.push(mp(0, id[P(sx, sy)])); int goal = id[P(tx, ty)]; while(!q.empty()){ int c = q.top().second; double cost = q.top().first; q.pop(); if(v.count(c)) continue; v.insert(c); if(c == goal){ printf("%.3f\n", -cost); break; } rep(i, e[c].size()){ double nc = cost - e[c][i].second; q.push(mp(nc, e[c][i].first)); } } } return 0; }