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. wpf DataGrid相关总结

    1.去掉外边蓝框,设置BorderThickness="0"

  2. jar打包exe选型

    网上一搜有篇文章写了9中不同工具方法,最后使用launch4j,其实就一点开源免费. launch4j>bsd3协议(可免费商用),像exe4j需要license. 经过摸索终于搞定一键启动并且 ...

  3. 配置全局路由表和VRF路由表之间的路由泄漏

    1.拓扑图 2.R1配置 R1#sho run Building configuration... Current configuration : 1360 bytes ! upgrade fpd a ...

  4. 为什么手游选择lua热更新方案。

    https://www.zhihu.com/question/29603593 主要因为iOS系统的原因. 在这个知乎问题里,有两条回答,能解释我的疑惑.如下两个图. 我个人总结为,编译型语言(C#) ...

  5. 有null值的子查询,子查询加排序,速度大幅提升

    意外发现,如果子查询结果有大量null值,加上一个排序,最后查询速度飞起

  6. Win10微软官方镜像iso文件下载

    1.转到下载页面2.按F12后点击小窗口左上角的手机图标3:刷新页面开始下载(win10.iso:链接)

  7. httpcanary高级版--不闪退!!!!

    地址 https://wwm.lanzouw.com/iOf7Hz11s4j 密码:45of

  8. git通过ssh方式免密克隆代码仓库

    git上添加ssh公钥 略过 终端命令行 格式: git clone ssh://[user@]host.xz[:port]/path/to/repo.git/ 栗子: git clone ssh:/ ...

  9. Echarts xAxis、yAxis

    2017年08月06日 09:10:12 数据架构师 阅读数:37641更多 所属专栏: Echarts数据可视化    版权声明:本文为博主原创文章,转载请注明来源.开发合作联系82548597@q ...

  10. Windows MFC HTTP POST请求 函数流程

    Windows MFC HTTP POST请求 函数流程 1 CString m_strHttpUrl(_T("http://10.200.80.86:8090/course/upload& ...