#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const double PI = 4.0 * atan(1.0); static const double PI2 = 8.0 * atan(1.0); typedef long long ll; #ifndef DELTA_R #define DELTA_R (0) #endif #define ALL(c) (c).begin(), (c).end() const double EPS = 1e-8; const double INF = 1e12; typedef complex P; namespace std { bool operator < (const P& a, const P& b) { if (abs(a.real() - b.real()) > EPS){ return a.real() < b.real(); } if (abs(a.imag() - b.imag()) > EPS){ return a.imag() < b.imag(); } return false; } //double abs(const P& p) //{ // return hypot(p.real(), p.imag()); //} } double cross(const P& a, const P& b) { return imag(conj(a)*b); } double dot(const P& a, const P& b) { return real(conj(a)*b); } struct L { P ps[2]; L(const P& a, const P& b) { ps[0] = a; ps[1] = b; } P& operator[](int i) { return ps[i]; } const P& operator[](int i) const { return ps[i]; } bool operator==(const L& rh) const { return abs(ps[0] - rh[0]) < EPS && abs(ps[1] - rh[1]) < EPS; } bool operator<(const L& rh) const { return abs(ps[0] - rh[0]) > EPS ? ps[0] < rh[0] : ps[1] < rh[1]; } }; //typedef pair L; //struct L : public vector

{ // L(const P &a, const P &b) { // push_back(a); push_back(b); // } //}; typedef vector

G; struct C { P p; double r; C(const P &p, double r) : p(p), r(r) { } }; int ccw(P a, P b, P c) { b -= a; c -= a; if (cross(b, c) > 0) return +1; // counter clockwise if (cross(b, c) < 0) return -1; // clockwise if (dot(b, c) < 0) return +2; // c--a--b on line if (norm(b) < norm(c)) return -2; // a--b--c on line return 0; } bool intersectLL(const L &l, const L &m) { return abs(cross(l[1]-l[0], m[1]-m[0])) > EPS || // non-parallel abs(cross(l[1]-l[0], m[0]-l[0])) < EPS; // same line } bool intersectLS(const L &l, const L &s) { return cross(l[1]-l[0], s[0]-l[0])* // s[0] is left of l cross(l[1]-l[0], s[1]-l[0]) < EPS; // s[1] is right of l } bool intersectLP(const L &l, const P &p) { return abs(cross(l[1]-p, l[0]-p)) < EPS; } bool intersectSS(const L &s, const L &t) { return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 && ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0; } bool intersectSP(const L &s, const P &p) { return abs(s[0]-p)+abs(s[1]-p)-abs(s[1]-s[0]) < EPS; // triangle inequality } P projection(const L &l, const P &p) { double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]); return l[0] + t*(l[0]-l[1]); } P reflection(const L &l, const P &p) { return p + 2.0 * (projection(l, p) - p); } double distanceLP(const L &l, const P &p) { return abs(p - projection(l, p)); } double distanceLL(const L &l, const L &m) { return intersectLL(l, m) ? 0 : distanceLP(l, m[0]); } double distanceLS(const L &l, const L &s) { if (intersectLS(l, s)) return 0; return min(distanceLP(l, s[0]), distanceLP(l, s[1])); } double distanceSP(const L &s, const P &p) { const P r = projection(s, p); if (intersectSP(s, r)) return abs(r - p); return min(abs(s[0] - p), abs(s[1] - p)); } double distanceSS(const L &s, const L &t) { if (intersectSS(s, t)) return 0; return min(min(distanceSP(s, t[0]), distanceSP(s, t[1])), min(distanceSP(t, s[0]), distanceSP(t, s[1]))); } P crosspoint(const L &l, const L &m) { double A = cross(l[1] - l[0], m[1] - m[0]); double B = cross(l[1] - l[0], l[1] - m[0]); if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!! return m[0] + B / A * (m[1] - m[0]); } bool isOverlapped(const L& a, const L& b) { const P a0 = a[0]; const P a1 = a[1]; const P b0 = b[0]; const P b1 = b[1]; const P a01 = a1 - a0; const P b01 = b1 - b0; if (abs(a0- b0) < EPS && abs(a1 - b1) < EPS || abs(a0- b1) < EPS && abs(a1 - b0) < EPS){ return true; } return abs(cross(a01, b01)) < EPS && (intersectSP(a, b0) || intersectSP(a, b1) || intersectSP(b, a0) || intersectSP(b, a1)); } bool isSamePoints(const P& lh, const P& rh) { return abs(lh - rh) < EPS; } void combine(L& a, L& b) { P ps[] = {a[0], a[1], b[0], b[1]}; sort(ps, ps + 4); a = L(ps[0], ps[3]); } bool combine(vector& segments) { vector combined(segments.size()); const int n = segments.size(); for (int i = 0; i < n; ++i){ if (combined[i]){ continue; } L& a = segments[i]; for (int j = i + 1; j < n; ++j){ if (combined[j]){ continue; } L& b = segments[j]; if (isOverlapped(a, b)){ combine(a, b); combined[j] = true; } } } vector compressed; for (int i = 0; i < segments.size(); ++i){ if (combined[i]){ continue; } compressed.push_back(segments[i]); } swap(segments, compressed); return false; } double normalize(double theta) { while (theta < 0){ theta += PI2; } while (theta > PI2){ theta -= PI2; } return theta; } //void segmentArrangement(const vector &ss, vector >& graph, vector

&ps) { // for (int i = 0; i < ss.size(); ++i) { // O(n^2) // ps.push_back( ss[i][0] ); // ps.push_back( ss[i][1] ); // for (int j = i+1; j < ss.size(); ++j) // if (intersectSS(ss[i], ss[j])) // ps.push_back( crosspoint(ss[i], ss[j]) ); // } // sort(ALL(ps)); ps.erase(unique(ALL(ps)), ps.end()); // // graph.resize(ps.size()); // //Graph g(ps.size()); // for (int i = 0; i < ss.size(); ++i) { // vector< pair > list; // for (int j = 0; j < ps.size(); ++j) // if (intersectSP(ss[i], ps[j])) // list.push_back(make_pair(norm(ss[i][0]-ps[j]), j)); // sort(ALL(list)); // for (int j = 0; j+1 < list.size(); ++j) { // int a = list[j].second, b = list[j+1].second; // //g[a].push_back( Edge(a, b, abs(ps[a]-ps[b])) ); // //g[b].push_back( Edge(b, a, abs(ps[a]-ps[b])) ); // graph[a].push_back(b); // graph[b].push_back(a); // } // } // //return g; //} bool EQ(const P& a, const P& b) { return abs(a - b) < EPS; } #define index_of(ps, p) \ distance(ps.begin(), lower_bound(ps.begin(), ps.end(), p)) void segmentArrangement(const vector& segs, vector >& graph, vector

& pt) { vector< vector > V(segs.size()); for (int i = 0; i < segs.size(); ++i) { pt.push_back( segs[i][0] ); pt.push_back( segs[i][1] ); V[i].push_back(0); V[i].push_back(1); for (int j = i+1; j < segs.size(); ++j) { L a = segs[i], b = segs[j]; if (intersectSS(a, b)) { double D = cross(b[1]-b[0], a[1]-a[0]); if (abs(D) < EPS){ continue; } double t = cross(b[1]-b[0], b[0]-a[0]) / D; double s = cross(a[0]-b[0], a[1]-a[0]) / D; V[i].push_back(t); V[j].push_back(s); pt.push_back( a[0]+(a[1]-a[0])*t ); } } } sort(pt.begin(), pt.end()); pt.erase(unique(pt.begin(), pt.end()), pt.end()); graph.clear(); graph.resize(pt.size()); //graph g(pt.size()); for (int i = 0; i < V.size(); ++i) { vector& cut = V[i]; sort(cut.begin(), cut.end()); cut.erase(unique(cut.begin(), cut.end(), EQ), cut.end()); for (int j = 0; j+1 < cut.size(); ++j) { P a = segs[i][0] + (segs[i][1] - segs[i][0]) * cut[j]; P b = segs[i][0] + (segs[i][1] - segs[i][0]) * cut[j+1]; int src = index_of(pt, a), dst = index_of(pt, b); //g[src].push_back( edge(src, dst, abs(a-b)) ); //g[dst].push_back( edge(dst, src, abs(a-b)) ); graph[src].push_back(dst); graph[dst].push_back(src); } } //return g; } double manhattanDistance(const P& a, const P& b) { return abs(a.real() - b.real()) + abs(a.imag() - b.imag()); } #define curr(points, i) points[i] #define next(points, i) points[(i+1)%points.size()] enum { OUT, ON, IN }; int contains(const vector

& points, const P& p) { bool in = false; for (int i = 0; i < points.size(); ++i) { P a = curr(points,i) - p, b = next(points,i) - p; if (imag(a) > imag(b)) swap(a, b); if (imag(a) <= 0 && 0 < imag(b)) if (cross(a, b) < 0) in = !in; if (cross(a, b) == 0 && dot(a, b) <= 0) return ON; } return in ? IN : OUT; } bool isErode(const P& p, const vector

& points, double R) { const int n = points.size(); for (int i = 0; i < n; ++i){ L l(points[i], points[(i + 1) % n]); double bestDistance = INF; if (abs(l[0].real() - l[1].real()) > EPS){ if (l[0].real() < p.real() + EPS && p.real() < l[1].real() + EPS || l[1].real() < p.real() + EPS && p.real() < l[0].real() + EPS){ const P cp = crosspoint(l, L(p, p + P(0, 1))); bestDistance = min(bestDistance, manhattanDistance(p, cp)); } } if (abs(l[0].imag() - l[1].imag()) > EPS){ if (l[0].imag() < p.imag() + EPS && p.imag() < l[1].imag() + EPS || l[1].imag() < p.imag() + EPS && p.imag() < l[0].imag() + EPS){ const P cp = crosspoint(l, L(p, p + P(1, 0))); bestDistance = min(bestDistance, manhattanDistance(p, cp)); } } bestDistance = min(bestDistance, manhattanDistance(l[0], p)); bestDistance = min(bestDistance, manhattanDistance(l[1], p)); if (bestDistance + EPS < R){ return true; } } return false; } //#define METAPOST #ifdef METAPOST ofstream ofs("metapost.mp"); int figureIndex = 1; P scale(const P& p, double minX, double maxX, double minY, double maxY, double left, double right, double bottom, double top) { return P((p.real() - minX) / (maxX - minX) * (right - left) + left, (p.imag() - minY) / (maxY - minY) * (top - bottom) + bottom); } #endif int main() { //ifstream cin("F1.in"); int N; double R; for (; cin >> N >> R && (N || R);){ R += DELTA_R; const P deltas[] = {P(R, 0), P(0, R), P(-R, 0), P(0, -R)}; vector

points; vector segments; for (int i = 0; i < N; ++i){ double x, y; cin >> x >> y; const P p(x, y); points.push_back(p); //各頂点を中心とし、一辺の長さがRの正方形を追加 if (R){ for (int j = 0; j < 4; ++j){ segments.push_back(L(p + deltas[j], p + deltas[(j + 1) % 4])); } } } for (int i = 0; i < N; ++i){ //各辺からdelta[j]離れた線分を追加 const L segment(points[i], points[(i + 1) % N]); for (int j = 0; j < (R ? 4 : 1); ++j){ segments.push_back(L(segment[0] + deltas[j], segment[1] + deltas[j])); } } //重複する線を全て統合する while (combine(segments)); vector > graph; vector

crossPoints; segmentArrangement(segments, graph, crossPoints); segments.clear(); #ifdef METAPOST vector outerSegments; #endif for (int from = 0; from < graph.size(); ++from){ const vector& edges = graph[from]; for (vector::const_iterator it = edges.begin(); it != edges.end(); ++it){ const int to = *it; const L l(crossPoints[from], crossPoints[to]); const P middlePoint = (crossPoints[from] + crossPoints[to]) * 0.5; if (!isErode(middlePoint, points, R) && contains(points, middlePoint)){ segments.push_back(l); #ifdef METAPOST } else { outerSegments.push_back(l); #endif } } } while (combine(segments)); #ifdef METAPOST const double left = 5; const double right = 590; const double bottom = 5; const double top = 590; double minX = INF; double maxX = -INF; double minY = INF; double maxY = -INF; for (vector::iterator it = segments.begin(); it != segments.end(); ++it){ const L& l = *it; for (int i = 0; i < 2; ++i){ minX = min(minX, l[i].real()); maxX = max(maxX, l[i].real()); minY = min(minY, l[i].imag()); maxY = max(maxY, l[i].imag()); } } for (vector::iterator it = outerSegments.begin(); it != outerSegments.end(); ++it){ const L& l = *it; for (int i = 0; i < 2; ++i){ minX = min(minX, l[i].real()); maxX = max(maxX, l[i].real()); minY = min(minY, l[i].imag()); maxY = max(maxY, l[i].imag()); } } if (maxX - minX < maxY - minY){ maxX = minX + maxY - minY; } else { maxY = minY + maxX - minX; } ofs << "beginfig(" << figureIndex++ << ")" << endl; for (int i = 0; i < crossPoints.size(); ++i){ const P a = scale(crossPoints[i], minX, maxX, minY, maxY, left, right, bottom, top); if (!isErode(a, points, R) && contains(points, a)){ ofs << "\tdraw " << a << " withpen pencircle scaled 3bp;" << endl; } else { ofs << "\tdraw " << a << " withpen pencircle scaled 1bp;" << endl; } } for (vector::iterator it = outerSegments.begin(); it != outerSegments.end(); ++it){ const L& l = *it; const P a = scale(l[0], minX, maxX, minY, maxY, left, right, bottom, top); const P b = scale(l[1], minX, maxX, minY, maxY, left, right, bottom, top); ofs << "\tdraw " << a << "--" << b << " withcolor .8white;" << endl; } for (int i = 0; i < points.size(); ++i){ const P a = scale(points[i], minX, maxX, minY, maxY, left, right, bottom, top); const P b = scale(points[(i + 1) % points.size()], minX, maxX, minY, maxY, left, right, bottom, top); ofs << "\tdraw " << a << "--" << b << " dashed evenly;" << endl; } for (vector::iterator it = segments.begin(); it != segments.end(); ++it){ const L& l = *it; const P a = scale(l[0], minX, maxX, minY, maxY, left, right, bottom, top); const P b = scale(l[1], minX, maxX, minY, maxY, left, right, bottom, top); ofs << "\tdraw " << a << "--" << b << ";" << endl; } for (double x = -100; x <= 100 + EPS; x += 50){ const P a = scale(P(x, -100), minX, maxX, minY, maxY, left, right, bottom, top); const P b = scale(P(x, 100), minX, maxX, minY, maxY, left, right, bottom, top); const P c = scale(P(-100, x), minX, maxX, minY, maxY, left, right, bottom, top); const P d = scale(P(100, x), minX, maxX, minY, maxY, left, right, bottom, top); ofs << "\tdraw " << a << "--" << b << " withcolor .5white dashed evenly;" << endl; ofs << "\tdraw " << c << "--" << d << " withcolor .5white dashed evenly;" << endl; } ofs << "endfig;" << endl << endl; #endif double answer = 0; for (vector::iterator it = segments.begin(); it != segments.end(); ++it){ const L& l = *it; answer += abs(l[0] - l[1]); } //answer *= 0.5; printf("%.10lf\n", answer); } #ifdef METAPOST ofs << "end." << endl; #endif }