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}}RangeCur​​RangeCur​​​RangeCur​:

扫一遍即可

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的更多相关文章

  1. UVA 10641 - Barisal Stadium(DP + 几何)

    题目链接:10641 - Barisal Stadium 题意:逆时针给定n个点,在给m个灯,每一个灯有一个花费,要求最小花费使得全部边能被灯照到 思路:用向量叉积推断向量的顺逆时针关系,从而预处理出 ...

  2. 【Uva 10641】 Barisal Stadium

    [Link]: [Description] 输入一个凸n(3≤n≤30)边形体育馆和多边形外的m(1≤m≤1000)个点光源,每个点光 源都有一个费用值.选择一组点光源,照亮整个多边形,使得费用值总和 ...

  3. [Uva10641]Barisal Stadium(区间dp)

    题意:按照顺时针给出操场的周边点,然后给出周围可以建设照明灯的位置,以及在该位置建设照明灯的代价,照明灯照射的范围与操场的边界相切,现在要求一个最小的花费,要求操场的所有边都被照射到. 解题关键:预处 ...

  4. [SQL]LeetCode601. 体育馆的人流量 | Human Traffic of Stadium

    SQL架构 Create table If Not Exists stadium (id int, visit_date DATE NULL, people int) Truncate table s ...

  5. Zjnu Stadium(加权并查集)

    Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  6. hdu 3047–Zjnu Stadium(带权并查集)

    题目大意: 有n个人坐在zjnu体育馆里面,然后给出m个他们之间的距离, A B X, 代表B的座位比A多X. 然后求出这m个关系之间有多少个错误,所谓错误就是当前这个关系与之前的有冲突. 分析: 首 ...

  7. [codeforces 325]B. Stadium and Games

    [codeforces 325]B. Stadium and Games 试题描述 Daniel is organizing a football tournament. He has come up ...

  8. hdu 3074 Zjnu Stadium (带权并查集)

    Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  9. 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:  ...

  10. hdu3047 Zjnu Stadium【带权并查集】

    <题目链接> <转载于 >>> > 题目大意: 有n个人坐在zjnu体育馆里面,然后给出m个他们之间的距离, A B X, 代表B的座位比A多X. 然后求出这 ...

随机推荐

  1. 通过Jenkins在远程服务器上执行shell脚本

    1.Jenkins安装Publish over SSH插件 下载安装Publish over SSH插件 2.配置服务器相关信息 要先在jenkins所在的机器上生成秘钥.生成方式为: ssh-key ...

  2. oracle学习之索引的介绍

    在关系型数据库中,用户查找数据与行的物理位置无关紧要.为了能够找到数据,表中的每一行均用一个rowid来标识,rowid能够标识数据库中某一行的具体位置.当Oracle数据库中存储海量的记录时,就意味 ...

  3. BIP拓展js的使用

    __app.define("common_VM_Extend.js", function () {   var selectData = null;   var common_VM ...

  4. 解决每次centos7执行java --version git --version等命令时都要重新source /etc/profile后才能执行,否则找不到命令-转载

      linux mint 我们通常将环境变量设置在/etc/profile这个文件中,这个文件是全局的. /etc/profile:在登录时,操作系 统定制用户环境时使用的第一个文件 ,此文件为系统的 ...

  5. C++ primer笔记 -变量和基本类型

    由于头文件会被包含在多个源文件中,所以不应该含有变量或者函数的定义.但又三个列外: 1.头文件可以定义类 2.值在编译时就已经知道的const对象(const对象默认为定义它的文件的局部变量,即在.c ...

  6. Python中的容器、迭代器、生成器

    容器是一系列元素的集合,str.list.set.dict.file.sockets对象都可以看作是容器,容器都可以被迭代(用在for,while等语句中),因此他们被称为可迭代对象. 可迭代对象实现 ...

  7. 【剑指Offer】【链表】合并两个排序的链表

    题目:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. A:若链表1为空,则合并后的链表头结点为pHead2:若链表2为空,则合并后的链表头结点为pHead ...

  8. drf从入门到飞升仙界 09

    接口文档 # 1.前后端分离 - 后端:写接口 - 前端:根据接口写app,小程序,pc端 # 2.作为后端开发 - 我们应该清楚: ---> /api/v1/login/ ---> 登录 ...

  9. macOS 常用键盘快捷键大全

    对于初次接触 macOS 的朋友来说,除了要寻找不同的 APP 软件之外,还有一件事情也直接影响着使用电脑的效率,那就是 - 键盘快捷键! 与 Windows 的差异 我们先来认识一下苹果 Mac 键 ...

  10. (Jmeter笔记)jmeter连接数据库(mysql)

    下载mysql连接驱动 地址:https://dev.mysql.com/downloads/connector/j/ ****把mysql连接驱动放在Jmeter/lib目录下**** >&g ...