这道题还是没思路,大致搜了下才知道是局部搜索。由于目标函数(到各个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;
}