照亮体育馆 Barisal Stadium

UVA10641
题目为逆时针顺序编号,这里直接将数组开两倍来处理环。(然而不知为啥开到1000也能过)
定义:
Corners[i]Corners[i]Corners[i]为体育馆点的坐标。
Lights[i]Lights[i]Lights[i]为灯的坐标及费用。
IsShineOnCur[i]IsShineOn_{Cur}[i]IsShineOnCur[i]表示第CurCurCur盏灯是否能照到iii,用于计算范围。
RangeCurRange_{Cur}RangeCur为第CurCurCur盏灯的照射范围,从LeftLeftLeft到RightRightRight,用于初始化dpdpdp
dp[Left][Right]dp[Left][Right]dp[Left][Right]为从第LeftLeftLeft盏灯照到第RightRightRight盏灯的最少花费。
初始化IsShineOnCur[i]\pmb{IsShineOn_{Cur}[i]}IsShineOnCur[i]IsShineOnCur[i]IsShineOnCur[i]:
令A、BA、BA、B两点为体育馆的两点,CCC为体育馆的一盏灯,那么CCC要想照亮边ABABAB,那么必须有0∘<∠BAC<180∘0^{\circ}< ∠BAC< 180^{\circ}0∘<∠BAC<180∘(手动转一转就知道了)

因为有:
sin(∠BAC)=AB⃗×AC⃗sin(∠BAC)=\vec{AB}×\vec{AC}sin(∠BAC)=AB×AC并且当sinθ>0sin\theta>0sinθ>0时,θ∈(0∘,180∘)\theta\in(0^{\circ},180^{\circ})θ∈(0∘,180∘)。
因此只要叉乘大于0即可。注意是逆时针的顺序。
//Cur为灯编号
void InitIsShineOn(const int& Cur) {
memset(IsShineOn, false, sizeof(IsShineOn));
for (int i = 1; i <= N; ++i) {
//i以及i的下一个点位体育馆的点
int&& Position = i % N + 1;
//如果叉乘大于0
IsShineOn[i] =
(Lights[Cur].x - Corners[i].x) * (Corners[Position].y - Corners[i].y)
>
(Corners[Position].x - Corners[i].x) * (Lights[Cur].y - Corners[i].y);
}
return;
}
初始化RangeCur\pmb{Range_{Cur}}RangeCurRangeCurRangeCur:
扫一遍即可
void InitRange(const int& Cur) {
if (IsShineOn[1] && IsShineOn[N]) {
Range.Left = N;
Range.Right = 1;
while (IsShineOn[Range.Left]) {
--Range.Left;
}
while (IsShineOn[Range.Right]) {
++Range.Right;
}
++Range.Left;
--Range.Right;
Range.Right += N;
}
else {
Range.Left = 1;
Range.Right = N;
while (!IsShineOn[Range.Left]) {
++Range.Left;
}
while (!IsShineOn[Range.Right]) {
--Range.Right;
}
}
return;
}
dp初始化:
dp=infif(第Cur盏灯能照亮Left到Right)dp[Left][Right]=min(dp[Left][Right],Lights[i].Cost])dp=inf\\if(第Cur盏灯能照亮Left到Right)\\dp[Left][Right]=min(dp[Left][Right],Lights[i].Cost])dp=infif(第Cur盏灯能照亮Left到Right)dp[Left][Right]=min(dp[Left][Right],Lights[i].Cost])
//判断第Cur盏灯能否照亮(Left,Right)的范围
bool Judgt(const int& Left, const int& Right) {
return
Range.Left - N <= Left && Range.Right - N >= Right
||
Range.Left <= Left && Range.Right >= Right
||
Range.Left + N <= Left && Range.Right + N >= Right;
}
void InitDP(const int& Cur) {
for (int Length = 0; Length < N; ++Length) {
for (int Left = 1; Left <= 2 * N - 1; ++Left) {
int&& Right = Left + Length;
if (Right > 2 * N - 1) {
break;
}
if (Judgt(Left, Right)) {
dp[Left][Right] = min(dp[Left][Right], Lights[Cur].Cost);
}
}
}
return;
}
转移方程:
dp[Left][Right]=min(dp[Left][k]+dp[k+1][Right])Left≤k<Rightdp[Left][Right]=min(dp[Left][k]+dp[k+1][Right])\\Left\leq k<Rightdp[Left][Right]=min(dp[Left][k]+dp[k+1][Right])Left≤k<Right经典的区间dpdpdp
最后答案为min(dp[i][i+N−1]),(1≤1≤N)min(dp[i][i+N-1]),(1\leq 1\leq N)min(dp[i][i+N−1]),(1≤1≤N)(双倍数组处理环的答案)
AC代码:
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
constexpr static long long inf = 0x3f3f3f3f3f3f3f3f;
struct Corner {
double x, y;
}Corners[31];
struct Light {
double x, y;
long long Cost;
}Lights[1001];
struct {
int Left, Right;
}Range;
int N, M;
bool IsShineOn[1001]{ false };
long long dp[1001][1001];
bool Input() {
cin >> N;
if (!N) {
return false;
}
for (int i = 1; i <= N; ++i) {
cin >> Corners[i].x >> Corners[i].y;
}
cin >> M;
for (int i = 1; i <= M; ++i) {
cin >> Lights[i].x >> Lights[i].y >> Lights[i].Cost;
}
return true;
}
void InitIsShineOn(const int& Cur) {
memset(IsShineOn, false, sizeof(IsShineOn));
for (int i = 1; i <= N; ++i) {
int&& Position = i % N + 1;
IsShineOn[i] =
(Lights[Cur].x - Corners[i].x) * (Corners[Position].y - Corners[i].y)
>
(Corners[Position].x - Corners[i].x) * (Lights[Cur].y - Corners[i].y);
}
return;
}
void InitRange(const int& Cur) {
if (IsShineOn[1] && IsShineOn[N]) {
Range.Left = N;
Range.Right = 1;
while (IsShineOn[Range.Left]) {
--Range.Left;
}
while (IsShineOn[Range.Right]) {
++Range.Right;
}
++Range.Left;
--Range.Right;
Range.Right += N;
}
else {
Range.Left = 1;
Range.Right = N;
while (!IsShineOn[Range.Left]) {
++Range.Left;
}
while (!IsShineOn[Range.Right]) {
--Range.Right;
}
}
return;
}
bool Judgt(const int& Left, const int& Right) {
return
Range.Left - N <= Left && Range.Right - N >= Right
||
Range.Left <= Left && Range.Right >= Right
||
Range.Left + N <= Left && Range.Right + N >= Right;
}
void InitDP(const int& Cur) {
for (int Length = 0; Length < N; ++Length) {
for (int Left = 1; Left <= 2 * N - 1; ++Left) {
int&& Right = Left + Length;
if (Right > 2 * N - 1) {
break;
}
if (Judgt(Left, Right)) {
dp[Left][Right] = min(dp[Left][Right], Lights[Cur].Cost);
}
}
}
return;
}
void Compute() {
for (int Length = 0; Length < N; ++Length) {
for (int Left = 1; Left <= 2 * N - 1; ++Left) {
int&& Right = Left + Length;
if (Right > 2 * N - 1) {
break;
}
for (int k = Left; k < Right; ++k) {
if (dp[Left][k] == inf && dp[k + 1][Right] == inf) {
continue;
}
dp[Left][Right] = min(dp[Left][Right], dp[Left][k] + dp[k + 1][Right]);
}
}
}
}
long long DP() {
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= M; ++i) {
InitIsShineOn(i);
InitRange(i);
InitDP(i);
}
Compute();
long long Ans = inf;
for (int i = 1; i <= N; ++i) {
Ans = min(Ans, dp[i][i + N - 1]);
}
return Ans;
}
int main() {
while (Input()) {
long long&& Ans = DP();
if (Ans == inf) {
puts("Impossible.");
}
else {
cout << Ans << endl;
}
}
return 0;
}
照亮体育馆 Barisal Stadium的更多相关文章
- UVA 10641 - Barisal Stadium(DP + 几何)
题目链接:10641 - Barisal Stadium 题意:逆时针给定n个点,在给m个灯,每一个灯有一个花费,要求最小花费使得全部边能被灯照到 思路:用向量叉积推断向量的顺逆时针关系,从而预处理出 ...
- 【Uva 10641】 Barisal Stadium
[Link]: [Description] 输入一个凸n(3≤n≤30)边形体育馆和多边形外的m(1≤m≤1000)个点光源,每个点光 源都有一个费用值.选择一组点光源,照亮整个多边形,使得费用值总和 ...
- [Uva10641]Barisal Stadium(区间dp)
题意:按照顺时针给出操场的周边点,然后给出周围可以建设照明灯的位置,以及在该位置建设照明灯的代价,照明灯照射的范围与操场的边界相切,现在要求一个最小的花费,要求操场的所有边都被照射到. 解题关键:预处 ...
- [SQL]LeetCode601. 体育馆的人流量 | Human Traffic of Stadium
SQL架构 Create table If Not Exists stadium (id int, visit_date DATE NULL, people int) Truncate table s ...
- Zjnu Stadium(加权并查集)
Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- hdu 3047–Zjnu Stadium(带权并查集)
题目大意: 有n个人坐在zjnu体育馆里面,然后给出m个他们之间的距离, A B X, 代表B的座位比A多X. 然后求出这m个关系之间有多少个错误,所谓错误就是当前这个关系与之前的有冲突. 分析: 首 ...
- [codeforces 325]B. Stadium and Games
[codeforces 325]B. Stadium and Games 试题描述 Daniel is organizing a football tournament. He has come up ...
- hdu 3074 Zjnu Stadium (带权并查集)
Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- LeetCode - 601. Human Traffic of Stadium
X city built a new stadium, each day many people visit it and the stats are saved as these columns: ...
- hdu3047 Zjnu Stadium【带权并查集】
<题目链接> <转载于 >>> > 题目大意: 有n个人坐在zjnu体育馆里面,然后给出m个他们之间的距离, A B X, 代表B的座位比A多X. 然后求出这 ...
随机推荐
- Jmeter 实现Json格式接口测试
接口Request Headers中的Content-Type和和charset 在"HTTP请求"中添加UTF-8 在"HTTP信息头管理器"中添加Conte ...
- 有关箭头函数的this知识
总结: 结果: 2,箭头函数正确的使用方法. 结果: 总结: 箭头函数不要直接在对象的属性上用.比如上面的函数3.
- abc289g题解
考虑枚举卖出的物品个数\(i\),把\(b_i\)从大到小排序. 题目的某人会买物品的条件转化为\(b_i\geq p_j-c_j\),这说明卖出的物品的集合是排序后\(b\)的一段前缀,且卖出\(i ...
- Windows Server 2012 R2安装.NET Framework4.7.1
1.KB2919442 https://www.microsoft.com/zh-cn/download/confirmation.aspx?id=42153 2.clearcompressionfl ...
- (读书笔记)基于CMMI的软件工程及实训指导------第一章软件工程基础
第一章------软件工程基础 1.软件工程基本原理 (1)按照软件生命周期的阶段划分制订计划,严格依据计划进行管理 (2)坚持进行阶段评审 (3)实行严格的产品控制 (4)采用现代程序设计技术 (5 ...
- Screw数据库文档生成神器
引入依赖 <dependency> <groupId>cn.smallbun.screw</groupId> <artifactId>screw-cor ...
- java功能-发送http请求
一.发送json public void test() throws IOException { //参数封装--------------------------------------------- ...
- vue的表单
你可以用 v-model 指令在表单控件元素上创建双向数据绑定. 输入框 实例中演示了 input 和 textarea 元素中使用 v-model 实现双向数据绑定: <!DOCTYPE ht ...
- Unity 消息机制
最近有新项目需要和同事合作开发,他做UI 我做网络层,做着做着发现 如果我们要相对独立完成自己的开发任务,那我们的代码耦合得减少,不然 一个人代码有大改的时候,另一个人也要进行大幅修改,这样不便于后期 ...
- express的使用:路由、中间件(二)
13.路由 1.express中的路由指客户端的请求与服务器处理函数间的映射关系 2.express中的路由由请求的类型,请求的URL地址,处理函数组成 3.app.METHOD(PATH,HANDL ...