#include #include #include #include #include #include #include #include #include #include using namespace std; #define read(a, b) scanf("%d %d", &a, &b) #define FOR(a, b) for(int a = 0; a < b; a++) #define file_in(a) freopen(a, "r", stdin) #define file_out(a) freopen(a, "w", stdout) static const int MAX_N = 100 + 8; static const int MAX_M = (3 * MAX_N) - 6; static const int MAX_SIZE = 10000 + 8; struct Point { int x, y; bool operator ==(Point a) { if(a.x == this->x and a.y == this->y) return true; return false; } }; Point make_point(int a, int b) { Point c; c.x = a; c.y = b; return c; } time_t curTime; const time_t maxTime = 2900; const time_t max_Time = 4900; bool noTime() { return clock() - curTime >= maxTime; } bool onSegment(Point p, Point q, Point r) { if (q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) && q.y <= max(p.y, r.y) && q.y >= min(p.y, r.y)) return true; return false; } int orientation(Point p, Point q, Point r) { int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); if (val == 0) return 0; return (val > 0)? 1: 2; } bool linesIntersect(Point p1, Point q1, Point p2, Point q2) { int o1 = orientation(p1, q1, p2); int o2 = orientation(p1, q1, q2); int o3 = orientation(p2, q2, p1); int o4 = orientation(p2, q2, q1); if (o1 != o2 && o3 != o4) return true; if (o1 == 0 && onSegment(p1, p2, q1)) return true; if (o2 == 0 && onSegment(p1, q2, q1)) return true; if (o3 == 0 && onSegment(p2, p1, q2)) return true; if (o4 == 0 && onSegment(p2, q1, q2)) return true; return false; } Point get_line_intersection(Point p0, Point p1, Point p2, Point p3) { Point s1, s2, i; i.x = -1; i.y = -1; s1.x = p1.x - p0.x; s1.y = p1.y - p0.y; s2.x = p3.x - p2.x; s2.y = p3.y - p2.y; if((-s2.x * s1.y + s1.x * s2.y) == 0) return i; int s, t; s = (-s1.y * (p0.x - p2.x) + s1.x * (p0.y - p2.y)) / (-s2.x * s1.y + s1.x * s2.y); t = ( s2.x * (p0.y - p2.y) - s2.y * (p0.x - p2.x)) / (-s2.x * s1.y + s1.x * s2.y); if (s >= 0 && s <= 1 && t >= 0 && t <= 1) { i.x = p0.x + (t * s1.x); i.y = p0.y + (t * s1.y); } return i; } int n, m; int centrals[MAX_N]; Point cityes[MAX_N]; vector wires[MAX_N]; void input() { read(n, m); FOR(i, n) read(cityes[i].x, cityes[i].y); FOR(i, m) { int from, to; read(from, to); from--; to--; wires[from].push_back(to); } } int maxCntrls; int curSolution[MAX_N]; int bestSolution[MAX_N]; //----------------------- bool usedC[MAX_N]; bool usedT[MAX_N]; bool pointOnSegment(Point a, Point b, Point p) { float slope, intercept; float left, top, right, bottom; float dx, dy; dx = a.x - b.x; dy = a.y - b.y; slope = dy / dx; intercept = a.y - slope * a.x; if(a.x < b.x) { left = a.x; right = b.x; } else { left = b.x; right = a.x; } if(a.y < b.y) { top = a.y; bottom = b.y; } else { top = a.y; bottom = b.y; } if( slope * p.x + intercept > (p.y - 0.01) && slope * p.x + intercept < (p.y + 0.01)) { if( p.x >= left && p.x <= right && p.y >= top && p.y <= bottom ) { return true; } else return false; } else return false; } void evaluate(int nums[]) { set > usd; vector< pair > lines; int line_central[MAX_N]; int city_central[MAX_N]; FOR(i, n) city_central[nums[i]] = i; FOR(i, n) FOR(j, wires[nums[i]].size()) { line_central[lines.size()] = i; lines.push_back(make_pair(cityes[i], cityes[city_central[wires[nums[i]][j]]])); } FOR(i, n) { FOR(j, n) { if(linesIntersect(lines[i].first, lines[i].second, cityes[j], cityes[j])) { if(lines[i].first == cityes[j]) continue; if(lines[i].second == cityes[j]) continue; if(lines[i].first.x == lines[j].first.x and lines[i].first.y == lines[j].first.y) continue; if(lines[i].first.x == lines[j].second.x and lines[i].first.y == lines[j].second.y) continue; if(lines[i].second.x == lines[j].first.x and lines[i].second.y == lines[j].first.y) continue; if(lines[i].second.x == lines[j].second.x and lines[i].second.y == lines[j].second.y) continue; return; } } } FOR(i, lines.size()) { //if(usd.count(make_pair(lines[i].first.x, lines[i].first.y)) or usd.count(make_pair(lines[i].second.x, lines[i].second.y))) continue; for(int j = i + 1; j < lines.size(); j++) { if(linesIntersect(lines[i].first, lines[i].second, lines[j].first, lines[j].second)) { Point cr = get_line_intersection(lines[i].first, lines[i].second, lines[j].first, lines[j].second); bool notSkip = false; if(cr.x == -1 and cr.y == -1) { if(lines[i].first == lines[j].first) if(pointOnSegment(lines[i].first, lines[i].second, lines[j].second) or pointOnSegment(lines[j].first, lines[j].second, lines[i].second)) notSkip = true; if(lines[i].first == lines[j].second) if(pointOnSegment(lines[i].first, lines[i].second, lines[j].first) or pointOnSegment(lines[j].first, lines[j].second, lines[i].second)) notSkip = true; if(lines[i].second == lines[j].first) if(pointOnSegment(lines[i].first, lines[i].second, lines[j].second) or pointOnSegment(lines[j].first, lines[j].second, lines[i].first)) notSkip = true; if(lines[i].second == lines[j].second) if(pointOnSegment(lines[i].first, lines[i].second, lines[j].first) or pointOnSegment(lines[j].first, lines[j].second, lines[i].first)) notSkip = true; } if(notSkip == false) { if(lines[i].first.x == lines[j].first.x and lines[i].first.y == lines[j].first.y) continue; if(lines[i].first.x == lines[j].second.x and lines[i].first.y == lines[j].second.y) continue; if(lines[i].second.x == lines[j].first.x and lines[i].second.y == lines[j].first.y) continue; if(lines[i].second.x == lines[j].second.x and lines[i].second.y == lines[j].second.y) continue; } //return; //usd.insert(make_pair(lines[i].first.x, lines[i].first.y)); nums[line_central[i]] = -1; break; } } } int cntrls = 0; FOR(i, n) if(nums[i] != -1) cntrls++; if(maxCntrls < cntrls) { maxCntrls = cntrls; FOR(i, n) bestSolution[i] = nums[i]; } } void solve() { int nums[n]; FOR(i, n) nums[i] = i; do { if(noTime()) return; int ev[n]; FOR(i, n) ev[i] = nums[i]; evaluate(ev); }while(next_permutation(nums, nums + n)); } int score(Point a, int b) { return sqrt((a.x - cityes[b].x)*(a.x - cityes[b].x) + (a.y - cityes[b].y)*(a.y - cityes[b].y)); } bool chechPoint(Point p, int central) { set > usd; vector< pair > lines; int line_central[MAX_N]; int city_central[MAX_N]; FOR(i, n) if(bestSolution[i] != -1) city_central[bestSolution[i]] = i; else city_central[bestSolution[i]] = -1; FOR(i, n) { if(bestSolution[i] == -1) continue; FOR(j, wires[bestSolution[i]].size()) { if(city_central[wires[bestSolution[i]][j]] >= n or city_central[wires[bestSolution[i]][j]] < 0) continue; line_central[lines.size()] = i; lines.push_back(make_pair(cityes[i], cityes[city_central[wires[bestSolution[i]][j]]])); } } FOR(j, wires[central].size()) { line_central[lines.size()] = central; lines.push_back(make_pair(p, cityes[city_central[wires[central][j]]])); } FOR(i, n) { if(linesIntersect(lines[i].first, lines[i].second, p, p)) { if(lines[i].first == p) continue; if(lines[i].second == p) continue; return false; } } FOR(i, n) { FOR(j, n) { if(linesIntersect(lines[i].first, lines[i].second, cityes[j], cityes[j])) { if(lines[i].first == cityes[j]) continue; if(lines[i].second == cityes[j]) continue; /*if(lines[i].first.x == lines[j].first.x and lines[i].first.y == lines[j].first.y) continue; if(lines[i].first.x == lines[j].second.x and lines[i].first.y == lines[j].second.y) continue; if(lines[i].second.x == lines[j].first.x and lines[i].second.y == lines[j].first.y) continue; if(lines[i].second.x == lines[j].second.x and lines[i].second.y == lines[j].second.y) continue;*/ return false; } } } FOR(i, lines.size()) { if(usd.count(make_pair(lines[i].first.x, lines[i].first.y)) or usd.count(make_pair(lines[i].second.x, lines[i].second.y))) continue; for(int j = i + 1; j < lines.size(); j++) { if(linesIntersect(lines[i].first, lines[i].second, lines[j].first, lines[j].second)) { Point cr = get_line_intersection(lines[i].first, lines[i].second, lines[j].first, lines[j].second); bool notSkip = false; if(cr.x == -1 and cr.y == -1) { if(lines[i].first == lines[j].first) if(pointOnSegment(lines[i].first, lines[i].second, lines[j].second) or pointOnSegment(lines[j].first, lines[j].second, lines[i].second)) notSkip = true; if(lines[i].first == lines[j].second) if(pointOnSegment(lines[i].first, lines[i].second, lines[j].first) or pointOnSegment(lines[j].first, lines[j].second, lines[i].second)) notSkip = true; if(lines[i].second == lines[j].first) if(pointOnSegment(lines[i].first, lines[i].second, lines[j].second) or pointOnSegment(lines[j].first, lines[j].second, lines[i].first)) notSkip = true; if(lines[i].second == lines[j].second) if(pointOnSegment(lines[i].first, lines[i].second, lines[j].first) or pointOnSegment(lines[j].first, lines[j].second, lines[i].first)) notSkip = true; } if(notSkip == false) { if(lines[i].first.x == lines[j].first.x and lines[i].first.y == lines[j].first.y) continue; if(lines[i].first.x == lines[j].second.x and lines[i].first.y == lines[j].second.y) continue; if(lines[i].second.x == lines[j].first.x and lines[i].second.y == lines[j].first.y) continue; if(lines[i].second.x == lines[j].second.x and lines[i].second.y == lines[j].second.y) continue; } return false; } } } return true; } Point getPos(int city, int central) { bool position_Ok = false; vector Pnts; Pnts.push_back(cityes[city]); set > usd; FOR(i, n) if(bestSolution[i] != -1) usd.insert(make_pair(cityes[i].x, cityes[i].y)); while(position_Ok == false) { if(clock() - curTime >= max_Time) return cityes[city]; FOR(i, Pnts.size()) { if(chechPoint(Pnts[i], central)) return Pnts[i]; } vector newPoints; FOR(i, Pnts.size()) { if(usd.count(make_pair(Pnts[i].x + 1, Pnts[i].y)) == 0 and Pnts[i].x + 1 <= 10000) { newPoints.push_back(make_point(Pnts[i].x + 1, Pnts[i].y)); usd.insert(make_pair(Pnts[i].x + 1, Pnts[i].y)); } if(usd.count(make_pair(Pnts[i].x + 1, Pnts[i].y + 1)) == 0 and Pnts[i].x + 1 <= 10000 and Pnts[i].y + 1 <= 10000) { newPoints.push_back(make_point(Pnts[i].x + 1, Pnts[i].y + 1)); usd.insert(make_pair(Pnts[i].x + 1, Pnts[i].y + 1)); } if(usd.count(make_pair(Pnts[i].x + 1, Pnts[i].y - 1)) == 0 and Pnts[i].x + 1 <= 10000 and Pnts[i].y - 1 >= 0) { newPoints.push_back(make_point(Pnts[i].x + 1, Pnts[i].y - 1)); usd.insert(make_pair(Pnts[i].x + 1, Pnts[i].y - 1)); } if(usd.count(make_pair(Pnts[i].x - 1, Pnts[i].y)) == 0 and Pnts[i].x - 1 >= 0) { newPoints.push_back(make_point(Pnts[i].x - 1, Pnts[i].y)); usd.insert(make_pair(Pnts[i].x - 1, Pnts[i].y)); } if(usd.count(make_pair(Pnts[i].x - 1, Pnts[i].y - 1)) == 0 and Pnts[i].x - 1 >= 0 and Pnts[i].y - 1 >= 0) { newPoints.push_back(make_point(Pnts[i].x - 1, Pnts[i].y - 1)); usd.insert(make_pair(Pnts[i].x - 1, Pnts[i].y - 1)); } if(usd.count(make_pair(Pnts[i].x - 1, Pnts[i].y + 1)) == 0 and Pnts[i].x - 1 >= 0 and Pnts[i].y + 1 <= 10000) { newPoints.push_back(make_point(Pnts[i].x - 1, Pnts[i].y + 1)); usd.insert(make_pair(Pnts[i].x - 1, Pnts[i].y + 1)); } if(usd.count(make_pair(Pnts[i].x, Pnts[i].y + 1)) == 0 and Pnts[i].y + 1 <= 10000) { newPoints.push_back(make_point(Pnts[i].x, Pnts[i].y + 1)); usd.insert(make_pair(Pnts[i].x, Pnts[i].y + 1)); } if(usd.count(make_pair(Pnts[i].x, Pnts[i].y - 1)) == 0 and Pnts[i].y - 1 >= 0) { newPoints.push_back(make_point(Pnts[i].x, Pnts[i].y - 1)); usd.insert(make_pair(Pnts[i].x, Pnts[i].y - 1)); } } Pnts = newPoints; } } int main() { curTime = clock(); //-------------------------- file_in("electricity.in"); file_out("electricity.out"); //-------------------------- input(); solve(); if(maxCntrls == 0) { printf("0\n"); return 0; } if(n > 30) { printf("%d\n", maxCntrls); if(maxCntrls == 0) return 0; FOR(i, n) if(bestSolution[i] != -1) { printf("%d %d %d %d\n", bestSolution[i] + 1, cityes[i].x, cityes[i].y, i + 1); } return 0; } vector centralsLeft; FOR(i, n) if(bestSolution[i] != -1) usedC[bestSolution[i]] = true; FOR(i, n) if(!usedC[i]) centralsLeft.push_back(i); FOR(i, n) { if(clock() - curTime >= max_Time) break; if(bestSolution[i] == -1) { bool bestPoss = false; Point bestPos; int bestCentral, indx; FOR(j, centralsLeft.size()) { Point pos = getPos(i, centralsLeft[j]); if(!bestPoss) { bestPos = pos; bestCentral = centralsLeft[j]; indx = j; } else if(score(bestPos, i) < score(pos, i)) { bestPos = pos; bestCentral = centralsLeft[j]; indx = j; } } maxCntrls++; bestSolution[i] = bestCentral; cityes[i] = bestPos; centralsLeft.erase(centralsLeft.begin() + indx); } } printf("%d\n", maxCntrls); if(maxCntrls == 0) return 0; FOR(i, n) if(bestSolution[i] != -1) { printf("%d %d %d %d\n", bestSolution[i] + 1, cityes[i].x, cityes[i].y, i + 1); } }