洛谷 P4529 [SCOI2003]切割多边形
时间:2020-03-26
本文章向大家介绍洛谷 P4529 [SCOI2003]切割多边形,主要包括洛谷 P4529 [SCOI2003]切割多边形使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
首先此题有一个显而易见的策略:每次切割都沿多边形的边缘。
那么就可以状压 dp 求解最小切割线,具体怎么转移也不必啰嗦了。
唯一的难点在于求解单次切割的长度。
不难发现,切 \(FG\) 的切割线正好是 \(FG\) 所在直线与已有的切割线集合 \(\{KJ, IL, AB, BC, CD, AD\}\) 的两个交点 \(M, N\) 之间的线段 \(MN\)。可以枚举所有已有切割线,求出 \(M, N\)。
为了表达没有斜率的直线,我使用一般式方程。解方程的时候一定要特判除 \(0\)、平行等毒瘤情况。
#include <cstdio>
#include <cmath>
#include <algorithm>
inline double min(const double& a, const double& b){
return a < b ? a : b;
}
const int MAXQ = 8 + 1;
double dp[1 << 8];
int n, m, q;
struct Point{
double x, y;
Point(){}
Point(double a, double b){
x = a, y = b;
}
bool operator<(const Point& b)const{
return std::fabs(x - b.x) < 1e-12 ? y < b.y : x < b.x;
}
bool operator>(const Point& b)const{
return std::fabs(x - b.x) < 1e-12 ? y > b.y : x > b.x;
}
}p[MAXQ];
struct Line{
double a, b, c;//一般式
Line(){}
Line(double __a, double __b, double __c){//参数构造直线
a = __a, b = __b, c = __c;
}
Line(Point __a, Point __b){//两点构造直线
if(std::fabs(__a.x - __b.x) < 1e-12)
a = 1, b = 0, c = -__a.x;
else
a = -__a.y + __b.y, b = __a.x - __b.x, c = -a * __a.x - b * __a.y;
}
Point operator^(const Line& __b)const{//重载 ^ 运算符求解两直线交点
if(std::fabs(b) < 1e-12 || std::fabs(__b.b) < 1e-12){
if(std::fabs(b) < 1e-12 && std::fabs(__b.b) < 1e-12)
return Point(1e18, 1e18);
else if(std::fabs(b) < 1e-12){
double x = -c / a, y = -(__b.a * x + __b.c) / __b.b;
return Point(x, y);
}
else{
double x = -__b.c / __b.a, y = -(a * x + c) / b;
return Point(x, y);
}
}
else if(std::fabs(a / b - __b.a / __b.b) < 1e-12)
return Point(1e18, 1e18);
else{
double x = -(c * __b.b - __b.c * b) / (a * __b.b - __b.a * b),
y = -(a * x + c) / b;
return Point(x, y);
}
}
}line[MAXQ];
inline double dist(Point a, Point b){
double x = a.x - b.x, y = a.y - b.y;
x *= x, y *= y;
return std::sqrt(x + y);
}
double value(int status, int node){
Point tmp, l = p[node], r = p[node % q + 1], re_l, re_r,
mid = Point((l.x + r.x) / 2, (l.y + r.y) / 2);
//re_l, re_r 是切割线与已有切痕的两个交点
if(std::fabs(line[node].a) < 1e-12)
re_l = line[node] ^ Line(1, 0, 0),
re_r = line[node] ^ Line(1, 0, -n);
else if(std::fabs(line[node].b) < 1e-12)
re_l = line[node] ^ Line(0, 1, 0),
re_r = line[node] ^ Line(0, 1, -m);
else if(line[node].a / line[node].b > 0)
re_l = std::max(line[node] ^ Line(0, 1, -m), line[node] ^ Line(1, 0, 0)),
re_r = std::min(line[node] ^ Line(0, 1, 0), line[node] ^ Line(1, 0, -n));
else if(line[node].a / line[node].b < 0)
re_l = std::max(line[node] ^ Line(0, 1, 0), line[node] ^ Line(1, 0, 0)),
re_r = std::min(line[node] ^ Line(0, 1, -m), line[node] ^ Line(1, 0, -n));
for(int i = 1; i <= q; ++i)
if(status & (1 << i - 1)){
tmp = line[node] ^ line[i];
if(tmp < mid)
re_l = std::max(re_l, tmp);
else if(tmp > mid)
re_r = std::min(re_r, tmp);
}
return dist(re_l, re_r);
}
int main(){
std::scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= q; ++i)
std::scanf("%lf%lf", &p[i].x, &p[i].y);
for(int i = 1; i <= q; ++i)
line[i] = Line(p[i], p[i % q + 1]);
for(int i = 1; i < (1 << q); ++i){
dp[i] = 1e18;
for(int j = 1; j <= q; ++j)
if(i & (1 << j - 1))
dp[i] = min(dp[i], dp[i ^ (1 << j - 1)] + value(i ^ (1 << j - 1), j));//朴素状压
}
std::printf("%lf\n", dp[(1 << q) - 1]);
return 0;
}
时间复杂度大概是 \(O(2 ^ n)\)?
原文地址:https://www.cnblogs.com/natsuka/p/12574930.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- IT运维面试问题总结-运维工具、开源应用(Ansible、Ceph、Docker、Apache、Nginx等)
- IT运维面试问题总结-数据库、监控、网络管理(NoSQL、MongoDB、MySQL、Prometheus、Zabbix)
- IT运维面试问题总结-LVS、Keepalived、HAProxy、Kubernetes、OpenShift等
- GitHub 标星 119K+!这些神器仅需一行代码即可下载全网视频!
- React进阶(2)-上手实践Redux-如何获取store的数据
- 关于Python3.9,这张「新特性必知图」就够了
- 3.Docker学习之Dockerfile
- n1.Docker命令参数一览表
- 2.Docker学习之基础使用
- 4-Kubernetes基础实战操作与配置
- n3-Kubernets对象字段描述一览
- n2-kubernetes操作命令详细一览
- 你不知道的this(2)
- import
- 你不知道的this(3)