uva 609 - Metal Cutting(暴力)

737 篇文章 0 订阅
232 篇文章 0 订阅

题目连接:uva 609 - Metal Cutting


题目大意:给出一个矩形,以及n个点,将切出以n个点为顶点的n边形,且最短的切割距离。点按照顺时针给出,不会有三个点在同一条直线上。


解题思路:要切的直线以及确定了,这要枚举切的顺序即可,用next_permutation枚举枚举所有切割顺序;对于每中切割顺序,将所有已经切过的边,以及边界保留,在切下一个边是,判断是否与前面的切边有交点,将所有交点保留,然后枚举切边线段外两点的最短距离。


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <algorithm>

using namespace std;
const int N = 10;
const double INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;

struct Point {
	double x, y;
	Point () { };
	Point (double x, double y) {
		this->x = x; this->y = y;
	}
}p[N];

struct Line {
	int id;
	double A, B, C;
	Point p1, p2;
	void set(Point a, Point b) {
		p1 = a; p2 = b;
		A = p2.y - p1.y;
		B = p1.x - p2.x;
		C = -(B * p1.y + A * p1.x);
	}
}line[N];

int n;
double r, l;
vector<Line> g;

bool cmp(Line a, Line b) {
	return a.id < b.id;
}

double distant (double x, double y) {
	return sqrt(x * x + y * y);
}

void init () {
	scanf("%lf%lf%d", &r, &l, &n);
	for (int i = 0; i < n; i++)
		scanf("%lf%lf", &p[i].x, &p[i].y);

	for (int i = 0; i < n; i++) {
		line[i].set(p[i], p[(i+1)%n]);
		line[i].id = i;
	}
}

inline bool judge (Point a, Point b, Point c, Point d) {
	int xup, xdown, yup, ydown;
	xup = xdown = yup = ydown = 0;
	
	double Max = max(c.x, d.x), Min = min(c.x, d.x);
	if (a.x - Max > -eps || b.x - Max > -eps) xup = 1;
	if (a.x - Min < eps || b.x - Min < eps) xdown = 1;

	Max = max(c.y, d.y); Min = min(c.y, d.y);
	if (a.y - Max > -eps || b.y - Max > -eps) yup = 1;
	if (a.y - Min < eps || b.y - Min < eps) ydown = 1;

	return xup + xdown + yup + ydown == 4;
}

inline Point find (Line a, Line b) {
	double x = (a.B * b.C - b.B * a.C) / (a.A * b.B - a.B * b.A);
	double y = (a.A * b.C - b.A * a.C) / (b.A * a.B - a.A * b.B);
	return Point(x, y);
}

inline double cat (int u) {
	Point v[20];
	int cnt = 0;

	for (int i = 0; i < g.size(); i++) {
		double Ai = g[i].A * line[u].B;
		double Bi = g[i].B * line[u].A;
		if (fabs(Ai - Bi) < eps) continue;

		Point k = find(g[i], line[u]);
		v[cnt++] = k;
	}

	double ans = INF;
	for (int i = 0; i < cnt; i++) {
		for (int j = i+1; j < cnt; j++) if (judge(v[i], v[j], line[u].p1, line[u].p2)) {
			double dis = distant(v[i].x - v[j].x, v[i].y - v[j].y);
			ans = min(ans, dis);
		}
	}
	return ans;
}

double del () {
	g.clear();
	Line t;
	t.set(Point(0, 0), Point(r, 0));
	g.push_back(t);
	t.set(Point(0, 0), Point(0, l));
	g.push_back(t);
	t.set(Point(r, l), Point(r, 0));
	g.push_back(t);
	t.set(Point(r, l), Point(0, l));
	g.push_back(t);

	double len = 0;
	for (int i = 0; i < n; i++) {
		len += cat(i);
		g.push_back(line[i]);
	}
	return len;
}

double solve () {
	double ans = INF;
	sort(line, line + n, cmp);
	do {
		ans = min(ans, del());
	} while (next_permutation(line, line + n, cmp));

	return ans;
}

int main () {
	int cas;
	scanf("%d", &cas);
	while (cas--) {
		init ();

		printf("Minimum total length = %.3lf\n", solve () );

		if (cas) printf("\n");
	}
	return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值