BZOJ 1390 [CEOI2008] Fence 题解

news/2025/2/9 12:17:02/

纪念一下,调了整整两周。

本题题意非常清晰,故不提供题意简述。

Solution

注意到 20 × 4 < 111 20\times 4<111 20×4<111,所以即使花 4 4 4 个点包住一棵树也是值的。所以我们考虑包住最多的树,这样一定是最优的。

所以我们对所有点求个凸包,然后对于每一棵树,如果它凸包所有边的同一侧,则它一定在凸包内,拿一个东西存下所有的树。

但是这样不一定是最优的,有一些点可能是无用的,删去之后仍然可以包住所有树。

我们考虑一个算法:对于凸包上的每相邻两条边(设为 A B → , B C → \overrightarrow{AB},\overrightarrow{BC} AB ,BC ),我都枚举一次。如果这个三角形内部并没有树,那么我们就删掉 B B B 这个点。

这样复杂度非常优秀,达到了 O ( n m ) O(nm) O(nm)

但是很遗憾,正确性是错的。为什么呢?请看下面这个图:

最优的选择是保留 A , C , D A,C,D A,C,D。但是,如果我们从 B B B 开始扫,你会发现 △ A B E \triangle ABE ABE 里根本就没有树,所以一开始就把 A A A 干掉了,怎么弄都得不到最优解。

看到 n , m ≤ 100 n,m\leq 100 n,m100,那我们就考虑一个暴力一些的算法。

先有一个结论:如果所有树出现在一个向量的同一侧,那么这个向量是有可能出现在最后的凸包内的。

所以我们暴力枚举任意两个点构成向量,如果合法我们就将这条边的边权赋为 1 1 1,否则设为正无穷。

然后就是一个 Floyd 求最小环问题了,时间复杂度 O ( n log ⁡ n + n 2 m + n 3 ) O(n\log n+n^2m+n^3) O(nlogn+n2m+n3),对于 n , m ≤ 100 n,m\leq 100 n,m100 的数据是非常松的。

当然,上面那个错误的做法,如果你对每个点都开始跑一遍,大概率是能得到最优解的,但是估计还是能 hack,这个我不太清楚,有点菜 qwq。

最后是一些阻碍了我很久的坑点:

  • 最后的点不一定全是在一开始求的凸包内,所以建图的时候不能只枚举凸包上的点而不枚举凸包内部的点;
  • 建图不要建双向边,因为向量带方向,反过来是不对的;
  • 如果你 94 分,请注意一个问题:如果所有树都不在凸包内,最小代价显然是不选点,直接输出 111 × m 111\times m 111×m。但是我们的 Floyd 是不允许不选点的,它会跑出来选两个点构成一个环。所以这种情况需要特判。
#include<bits/stdc++.h>
using namespace std;const double eps = 1e-8;
const int N = 100 + 10;
int n, m, idx = -1, hd;
int g[N][N];
struct node{double x, y;
} p[N], tree[N];
node st[N];
vector<int> inside;double getcro(node oo, node pp, node qq){return (pp.x - oo.x) * (qq.y - oo.y) - (qq.x - oo.x) * (pp.y - oo.y);
}double dis(node pp, node qq){return sqrt((pp.x - qq.x) * (pp.x - qq.x) + (pp.y - qq.y) * (pp.y - qq.y));
}bool cmp(node a, node b){double now = getcro(p[1], a, b);//叉积求面积 if(now < 0 || (now == 0 && dis(p[1], a) < dis(p[1], b)))return 1;return 0;
}bool isleft(node u, node s, node t){double f = getcro(u, s, t);return f >= eps;
}bool possible(node u, node v){for(int i=0;i<inside.size();i++){node pp = tree[inside[i]];if(!isleft(pp, v, u))return 0;}return 1;
}int main(){scanf("%d%d", &n, &m);for(int i=1;i<=n;i++){scanf("%lf%lf", &p[i].x, &p[i].y);if(idx == -1 || p[i].y < p[idx].y)idx = i;}for(int i=1;i<=m;i++)scanf("%lf%lf", &tree[i].x, &tree[i].y);swap(p[1], p[idx]);sort(p + 2, p + 1 + n, cmp);st[++hd] = p[1];for(int i=2;i<=n;i++){while(hd > 1 && !isleft(st[hd - 1], p[i], st[hd]))--hd;st[++hd] = p[i];}int cnt = 0, ans = 1e9;st[++hd] = p[1];for(int i=1;i<=m;i++){bool f = 1;for(int j=hd;j>1;j--){if(!isleft(st[j - 1], tree[i], st[j])){f = 0;break;}}if(f)inside.push_back(i), ++cnt;}if(!cnt)return printf("%d\n", m * 111), 0; for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){node u = p[i], v = p[j];if(i != j && possible(u, v))g[i][j] = 1;elseg[i][j] = 1e9;}}for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)g[i][j] = min(g[i][j], g[i][k] + g[k][j]);for(int i=1;i<=n;i++)ans = min(ans, g[i][i]);printf("%d\n", (m - cnt) * 111 + ans * 20);return 0;
}

http://www.ppmy.cn/news/576642.html

相关文章

General error: 1390 Prepared statement contains too many placeholders

欢迎加入PHP技术交流QQ群 370648191、201923866 今天遇到mysql占位符的问题。 问题背景是: 在做一个自己用的股票分析系统的时候&#xff0c;采集单只股票数据&#xff0c;可指定采集时间区间。采集完成后&#xff0c;一次性插入数据库。 题外话开始 (一些经验欠缺的&#xf…

POJ 1390:Blocks

问题描述 你们中的一些人可能玩过一个名为“块”的游戏。一行有n个块&#xff0c;每个框都有一个颜色。这是一个例子&#xff1a;金&#xff0c;银&#xff0c;银&#xff0c;银&#xff0c;银&#xff0c;青铜&#xff0c;青铜&#xff0c;青铜&#xff0c;金。相应的图片将如…

LeetCode 1390. 四因数

1. 题目 给你一个整数数组 nums&#xff0c;请你返回该数组中恰有四个因数的这些整数的各因数之和。 如果数组中不存在满足题意的整数&#xff0c;则返回 0 。 示例&#xff1a; 输入&#xff1a;nums [21,4,7] 输出&#xff1a;32 解释&#xff1a; 21 有 4 个因数&#x…

xtu oj 1390 字母计数

字母计数 题目描述 为了压缩一个只含小写英文字母的字符串&#xff0c;我们使用下面的方式表示它 任一字母c是表达式 任一字母c后接一个整数n也是一个表达式&#xff0c;表示把字母c重复n次&#xff0c;n是一个没有前导零的10进制整数&#xff0c;且 n≥2。 如果s1,s2是表达…

xtu 1390 字母计数 oj

字母计数 题目描述 为了压缩一个只含小写英文字母的字符串&#xff0c;我们使用下面的方式表示它 任一字母c是表达式任一字母c后接一个整数n也是一个表达式&#xff0c;表示把字母c重复n次&#xff0c;n是一个没有前导零的10进制整数&#xff0c;且 n≥2。如果s1,s2是表达式&am…

Error 1390: Prepared statement contains too many placeholders

当大量数据同时插入数据库时&#xff0c;出现了以下报错&#xff1a; Error 1390: Prepared statement contains too many placeholders经过搜索&#xff0c;发现这个问题&#xff0c;是由于SQL语句中占位符数量限制导致的。 MySQL官方文档 error 定义&#xff1a; Error num…

浙大1390 素数问题

浙大1390 素数问题 1390素数问题 Time Limit:1000MS Memory Limit:32768K Description:任何一个整数&#xff0c;都可以有多个素数相乘&#xff0c;现在给你一个数N(1< N<65535)&#xff0c;请你把它分成多个素数相乘。 Input:输入一个整数N&#xff0c;输入0表示结束. …

AI提高软件外包开发效率

最近几年AI技术取得了很大的进步&#xff0c;在一些领域甚至有突破性的进展&#xff0c;虽然无法预测未来AI会如何影响到人们的生活&#xff0c;但可以确定的是AI会在方方面面影响到大家的生活方式&#xff0c;也许未来五年内就会有一个明显的变化。今天和大家分享AI如何提高软…