这道题还是没思路,大致搜了下才知道是局部搜索。由于目标函数(到各个segment的距离之和)是凸函数之和,因而也是凸函数,所以局部最优解(即局部最小值)就是全局最优解,见http://stackoverflow.com/questions/2255889/local-optimums-in-electric-fences。
一个点到segment的距离用的是topcoder tutorial上面的方法:http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=geometry1
大神也做了这道题(https://www.byvoid.com/blog/usaco-522-electric-fences),用的是两遍扫描(似乎是先确定x,粗略确定y,第二遍再确定y)。我的粗暴搜索似乎还快些。
USER: chen chen [thestor1] TASK: fence3 LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.016 secs, 3504 KB] Test 2: TEST OK [0.011 secs, 3504 KB] Test 3: TEST OK [0.011 secs, 3504 KB] Test 4: TEST OK [0.011 secs, 3504 KB] Test 5: TEST OK [0.024 secs, 3504 KB] Test 6: TEST OK [0.022 secs, 3504 KB] Test 7: TEST OK [0.011 secs, 3504 KB] Test 8: TEST OK [0.016 secs, 3504 KB] Test 9: TEST OK [0.019 secs, 3504 KB] Test 10: TEST OK [0.011 secs, 3504 KB] Test 11: TEST OK [0.027 secs, 3504 KB] Test 12: TEST OK [0.024 secs, 3504 KB] All tests OK.YOUR PROGRAM ('fence3') WORKED FIRST TIME! That's fantastic -- and a rare thing. Please accept these special automated congratulations.
/* ID: thestor1 LANG: C++ TASK: fence3 */ #include <iostream> #include <fstream> #include <cmath> #include <cstdio> #include <cstring> #include <limits> #include <cassert> #include <string> #include <vector> #include <list> #include <set> #include <map> #include <queue> #include <stack> #include <algorithm> #include <cassert> #include <iomanip> using namespace std; const int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1}; double disttopoint(int x1, int y1, int x2, int y2) { return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); } class LineSegment { public: int x1, y1, x2, y2; double dist; LineSegment(int x1, int y1, int x2, int y2) : x1(x1), y1(y1), x2(x2), y2(y2) { dist = disttopoint(x1, y1, x2, y2); } }; int dot(int x1, int y1, int x2, int y2) { return x1 * x2 + y1 * y2; } int cross(int x1, int y1, int x2, int y2) { return x1 * y2 - y1 * x2; } double disttosegment(int x, int y, LineSegment &line) { if (dot(line.x2 - line.x1, line.y2 - line.y1, x - line.x2, y - line.y2) >= 0) { return disttopoint(x, y, line.x2, line.y2); } if (dot(line.x1 - line.x2, line.y1 - line.y2, x - line.x1, y - line.y1) >= 0) { return disttopoint(x, y, line.x1, line.y1); } return abs(cross(line.x2 - line.x1, line.y2 - line.y1, x - line.x1, y - line.y1) * 1.0 / line.dist); } double disttolines(int x, int y, std::vector<LineSegment> &linesegments) { double dist = 0; for (int i = 0; i < linesegments.size(); ++i) { dist += disttosegment(x, y, linesegments[i]); } return dist; } void dfs(int x, int y, std::vector<std::vector<bool> > &visited, std::vector<LineSegment> &linesegments, int &bestx, int &besty, double &bestdist) { visited[x][y] = true; int nx, ny; double dist; for (int d = 0; d < 4; ++d) { nx = x + dx[d], ny = y + dy[d]; if (nx < 0 || nx > 1000 || ny < 0 || ny > 1000 || visited[nx][ny]) { continue; } dist = disttolines(nx, ny, linesegments); if (dist <= bestdist) { bestdist = dist; bestx = nx, besty = ny; dfs(nx, ny, visited, linesegments, bestx, besty, bestdist); } } } int main() { ifstream fin("fence3.in"); int F; fin >> F; std::vector<LineSegment> linesegments; int x1, y1, x2, y2; for (int i = 0; i < F; ++i) { fin >> x1 >> y1 >> x2 >> y2; linesegments.push_back(LineSegment(x1 * 10, y1 * 10, x2 * 10, y2 * 10)); } fin.close(); // cout << "linesegments:" << endl; // for (int i = 0; i < linesegments.size(); ++i) // { // cout << i << ": " << linesegments[i].x1 << ", " << linesegments[i].y1 << ", " << linesegments[i].x2 << ", " << linesegments[i].y2 << "[" << linesegments[i].dist << "]" << endl; // } std::vector<std::vector<bool> > visited(1001, std::vector<bool>(1001, false)); int bestx = 0, besty = 0; double bestdist = disttolines(0, 0, linesegments); dfs(0, 0, visited, linesegments, bestx, besty, bestdist); ofstream fout("fence3.out"); fout << fixed << setprecision(1); fout << bestx / 10.0 << " " << besty / 10.0 << " " << bestdist / 10.0 << endl; fout.close(); return 0; }