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. oracle学习undo之事务槽和oracle的多种提交方式

    1.事务槽数量参数 每一个oracle数据块里面在数据块头部都有事务槽,事务槽的数量可以去查一下,如果数据库中的表T2: select INI_TRANS,MAX_TRANS from dba_tab ...

  2. lua-路径加载lua文件-函数返回值,访问lua文件中的变量

    lua文件如下: print("ddhdhh")function login(username,pswd)if username =="ms" and pswd ...

  3. 《TensorFlow+Keras自然语言处理实战》图书介绍

    #好书推荐##好书奇遇季#<TensorFlow+Keras自然语言处理实战>.当当京东天猫均有发售. https://item.jd.com/12788707.html 文后有本书配套源 ...

  4. mysql 取出分组后价格最高的数据

    如何用mysql 取出分组后价格最高的数据 ? 看到这个问题,就想到了用 max 函数和 group by 函数,先 group by 然后取得 max, 但是这样真的可以吗? 不可以 ! 为什么?  ...

  5. freeradius + mysql安装配置

    该文档参考http://t.zoukankan.com/FlyingPuPu-p-7772410.html安装,仅做了微调. 一.准备工作 安装编译FreeRadius所需要的依赖 #安装wget.g ...

  6. 10 个常用的 JS 工具库,80% 的项目都在用!

    Day.js 一个极简的处理时间和日期的 JavaScript 库,和 Moment.js 的 API 设计保持一样, 但体积仅有2KB. npm install dayjs 基本用法 import ...

  7. 你对USB了解吗?--USB 协议分析之 HID 设备

    1. 简述 USB HID类是USB设备的一个标准设备类,包括的设备非常多.HID类设备定义它属于人机交互操作的设备,用于控制计算机操作的一些方面,如USB鼠标.USB键盘.USB游戏操纵杆等.但HI ...

  8. Java语言程序设计课后小结

    运行结果:Size s = Size.SMALL;此时,s = SMALL.Size t = Size.LARGE:此时t = LARGE. System.out.println(s==t).由于s和 ...

  9. ionic 架构

    1.路由:rout,页面内容:html,页面css:scss,js脚本内容:ts 2.功能介绍 路由:负责组织每个页面. 页面css:scss,负责定制每个组件的内容,比如组件是iobag,那么在这个 ...

  10. /etc/login.defs 创建用户的默认设置文件

    /etc/login.defs 文件用于在创建用户时,对用户的一些基本属性做默认设置,例如指定用户 UID 和 GID 的范围,用户的过期时间,密码的最大长度,等等.需要注意的是,该文件的用户默认配置 ...