USACO Electric Fences 解题报告

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值