这场Gym全名是这个:2013-2014 CT S01E01: Extended 2000 ACM-ICPC East Central North America Regional Contest (ECNA 2000)

……太长了……于是直接用网址里的编号了……

其实这题代码还没写完……但是思路应该是对的,于是来挖个坑

贴个链接:codeforces.com/gym/100227,戳进一道题之后可以下载所有题目的pdf……

题意:

平面上有n个红点和m个蓝点,要求选出一个定点全部是红点的凸多边形,使得内部和边上都没有蓝点。求这样的多边形的最大面积,输出方案。n,m<=100。

解:

首先枚举所有三角形,然后判断三角形内有没有蓝点。

接下来枚举凸多边形上最左侧的一个点C。假想得到了一个凸多边形,从C向其他所有点连边,把这个凸多边形划分成一堆三角形。

对于一个以C为顶点的合法三角形ABC,可以连边A->B:vector(CA)×vector(CB)以及其反边。那么一个合法多边形(不一定凸,甚至不一定是简单多边形……)的面积就是从C出发再回到C的一个环的权值和的绝对值(除以2,这里就不管这么多了)。

但是这样是不行的……一来不能保证凸性,二来有正环上的图上怎么求最大环……我反正是不会做。

既然这样,是不是可以把图弄成DAG?

把所有点分成在C上面和在C下面的!对于上方的点,只有当叉积为负时才连边,下方相反。这样得到的就是DAG了~只要分别求出到上下两部分每个点的最长路,然后各枚举一个点就得到了一个(不一定凸)的多边形。而且方案也很好记录。

接下来考虑凸性。在DAG上DP的时候多记录一位,d[i][j]表示到了点i且上一个点是点j时的最长路。转移的时候判断一下是否满足凸性就好了……麻烦的地方在于合并。

对于一个点i求出所有合法的d[i][j],将所有的vector(ji)按照极角排序,并求出前缀最大值以及最大值的位置。接下来枚举上下各一个点,计算出极角,再在上下二分求出最值……方案也可以类似求。

这样整个复杂度就是O(m*n^3+n^3logn)……思维难度还是不错的……实现起来也挺麻烦的……好题啊~

UPD:才发现……根本没有必要排序二分啥的……枚举完上下的两点之后再O(n)找前驱就好了……总复杂度还是O(n^4)的。

代码:

由于有一些特殊情况,而且要输出方案,所以写了将近6kb,丑死了……

//CF Gym 100227 I
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
using namespace std;#define pair(x, y) make_pair(x, y)#define N 100
struct point {int x, y;inline void read() {scanf("%d%d", &x, &y);}
} p[N + 1], block[N + 1];
int n, m;inline int cross(const point &o, const point &a, const point &b) {return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
}struct edge {int next, node, w;
} e[N * N + 1];
int head[N + 1], tot;
bool valid[N + 1][N + 1][N + 1];
int dist[N + 1][N + 1], d[2][N + 1][N + 1], deg[N + 1];inline void addedge(int a, int b, int w) {e[++tot].next = head[a];head[a] = tot, e[tot].node = b, e[tot].w = w, ++deg[b];
}inline void initGraph() {memset(head, 0, sizeof head), tot = 0;memset(deg, 0, sizeof deg);
}void solve(int S, int d[][N + 1], bool up = false) {static int q[N + 1];int h = 0, t = 0;q[t++] = S, d[S][S] = 0;while (h < t) {int cur = q[h++];for (int i = head[cur]; i; i = e[i].next) {int node = e[i].node;if (!--deg[node]) q[t++] = node;for (int j = 1; j <= n; ++j) {if (d[cur][j] == INT_MIN) continue;if (cur != S && (up ^ (cross(p[j], p[cur], p[node]) < 0))) continue;if (d[node][cur] < d[cur][j] + e[i].w)d[node][cur] = d[cur][j] + e[i].w;}}}
}inline bool on(const point &a, const point &b, const point &c) {if (c.x < min(a.x, b.x) || c.x > max(a.x, b.x)) return false;if (c.y < min(a.y, b.y) || c.y > max(a.y, b.y)) return false;return true;
}int main(int argc, char* argv[]) {
#ifdef KANARIfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifscanf("%d", &n);for (int i = 1; i <= n; ++i) p[i].read();scanf("%d", &m);for (int i = 1; i <= m; ++i) block[i].read();for (int x = 1; x <= n; ++x)for (int y = x + 1; y <= n; ++y)for (int z = y + 1; z <= n; ++z) {bool ok = true;for (int i = 1; ok && i <= m; ++i) {int a = cross(p[x], block[i], p[y]);int b = cross(p[y], block[i], p[z]);int c = cross(p[z], block[i], p[x]);if (!a && on(p[x], p[y], block[i])) ok = false;if (!b && on(p[y], p[z], block[i])) ok = false; if (!c && on(p[z], p[x], block[i])) ok = false;if (a > 0 && b > 0 && c > 0) ok = false;if (a < 0 && b < 0 && c < 0) ok = false;}if (ok == true) {valid[x][y][z] = valid[x][z][y] = true;valid[y][x][z] = valid[y][z][x] = true;valid[z][x][y] = valid[z][y][x] = true;}}int ans = 0, nodes = 0;static int convex[N + 1];for (int c = 1; c <= n; ++c) {for (int a = 1; a <= n; ++a)for (int b = 1; b <= n; ++b)if (valid[c][a][b] || a == c || b == c) dist[a][b] = cross(p[c], p[a], p[b]);else dist[a][b] = INT_MAX;static int q[N + 1];int cnt = 0;for (int i = 1; i <= n; ++i)for (int j = 1; j <= n; ++j)d[0][i][j] = d[1][i][j] = INT_MIN;for (int i = 1; i <= n; ++i)if (p[i].x >= p[c].x && p[i].y >= p[c].y) q[++cnt] = i;initGraph();for (int x = 1; x <= cnt; ++x)for (int y = 1; y <= cnt; ++y)if (dist[q[x]][q[y]] < 0)addedge(q[x], q[y], -dist[q[x]][q[y]]);for (int x = 1; x <= cnt; ++x)if (q[x] != c) addedge(c, q[x], 0);solve(c, d[0], true);cnt = 0;for (int i = 1; i <= n; ++i)if (p[i].x >= p[c].x && p[i].y <= p[c].y) q[++cnt] = i;initGraph();for (int x = 1; x <= cnt; ++x)for (int y = 1; y <= cnt; ++y)if (dist[q[x]][q[y]] > 0 && dist[q[x]][q[y]] != INT_MAX)addedge(q[x], q[y], dist[q[x]][q[y]]);for (int x = 1; x <= cnt; ++x)if (q[x] != c) addedge(c, q[x], 0);solve(c, d[1]);bool updated = false;pair <int, int> up, down;for (int x = 1; x <= n; ++x) {if (!(p[x].x >= p[c].x && p[x].y >= p[c].y)) continue;for (int y = 1; y <= n; ++y) {if (!(p[y].x >= p[c].x && p[y].y <= p[c].y)) continue;if (dist[x][y] == INT_MAX) continue;int xl = -1, xcur = INT_MIN, yr = -1, ycur = INT_MIN;if (x != c) {for (int i = 1; i <= n; ++i)if (cross(p[i], p[x], p[y]) <= 0 && xcur < d[0][x][i])xcur = d[0][x][i], xl = i;} else xl = c, xcur = 0;if (xl == -1) continue;if (y != c) {for (int i = 1; i <= n; ++i)if (cross(p[x], p[y], p[i]) <= 0 && ycur < d[1][y][i])ycur = d[1][y][i], yr = i;} else yr = c, ycur = 0;if (yr == -1) continue;int cur = xcur + ycur + abs(dist[x][y]);if (cur > ans) {ans = cur, updated = true;up = pair(x, xl), down = pair(y, yr);}}}if (updated) {nodes = 0;convex[++nodes] = c;if (up.first != c) convex[++nodes] = up.first;for (int x = up.second, y = up.first; x != c; ) {int cur = d[0][y][x] - (-dist[x][y]);convex[++nodes] = x, y = x;for (int i = 1; i <= n; ++i)if (d[0][x][i] == cur && dist[i][x] <= 0) {x = i;break;}}reverse(convex + 2, convex + nodes + 1);if (up.first != down.first && down.first != c) convex[++nodes] = down.first;for (int x = down.second, y = down.first; x != c; ) {int cur = d[1][y][x] - dist[x][y];convex[++nodes] = x, y = x;for (int i = 1; i <= n; ++i)if (d[1][x][i] == cur && dist[i][x] >= 0) {x = i;break;}}reverse(convex + 2, convex + nodes + 1);}}printf("%d\n", nodes);if (nodes > 0) {printf("%d", convex[1]);for (int i = 2; i <= nodes; ++i) printf(" %d", convex[i]);printf("\n");}fclose(stdin);fclose(stdout);return 0;
}

CF Gym 100227 I题 题解相关推荐

  1. 枚举求解单词方阵(洛谷P1101题题解,Java语言描述)

    题目要求 P1101题目链接 分析 可以用DFS做,但我立下了个Flag,所以就用了朴素的枚举来做.... 结果,我的天哪,做了好几个小时-- 其实这种地图题,真的适合 DFS or BFS or D ...

  2. 线性存储的最短平均检索时间(洛谷P1253题题解,Java语言描述)

    题目要求 P1253题目链接 分析 很像 ~洛谷P1223题题解~,也是一种类似SJF的贪心法. 排个序,由于两个不大于10000的数,乘起来还是int,就使用int属性吧. 数据量小,所以Scann ...

  3. 快速幂||取余运算【模板】(洛谷P1226题题解,Java语言描述)

    题目要求 P1226题目链接 分析 标准的快速幂取模算法板子,之前这个算法我在这篇文章中讲过了:<快速幂算法详解&&快速幂取模算法详解>. 这里选择使用比较简单的API实现 ...

  4. 队列模拟约瑟夫问题(洛谷P1996题题解,Java语言描述)

    题目要求 P1996题目链接 分析 以前就研究过"约瑟夫环"问题: <单循环链表求解约瑟夫环问题(Java语言描述)> <杀人游戏~约瑟夫环(洛谷P1145题题解 ...

  5. 两分数相乘后约分的Cantor表(洛谷P1482题题解,Java语言描述)

    题目要求 P1482题目链接 分析 据说本题是这题的升级版-- → P1014题题解 升级的地方其实就是相乘之后约分. 约分需要求解最大公约数,gcd()是吧-- 但我这里偏偏懒得写gcd,就想用Ja ...

  6. 带前导0的数字三角形(洛谷P5721题题解,Java语言描述)

    题目要求 P5721题题解 分析 注意补0呀 AC代码(Java语言描述) import java.util.Scanner;public class Main {public static void ...

  7. 用任意合法序列建立一棵二叉树(洛谷P1305题题解,Java语言描述)

    前言 这题是极其麻烦极其麻烦的一道题(前提是你不知道它有套路)-- 我们不讲那些歪门邪道,我们正儿八经的解一下,想正经求解,很麻烦很麻烦... 题目要求 P1305题题解 分析 这题你看着容易,那是你 ...

  8. xdu1068暨2013陕西省赛C题题解

    xdu1068暨2013陕西省赛C题题解 题意 知道两个数列M和F,每次从M中选择一个人,和从F中选择的一个人配对,结果是Mi*Fj,请问所有配对情况中第k大的情况是多少. 笺释 先对M和F从小到大排 ...

  9. HDU各种比赛题题解(一)

    HDU各种比赛题题解(一) Gardon-DYGG Contest 1 HDU1178 Heritage from father[水题] - 海岛Blog - CSDN博客 HDU1181 变形课[D ...

最新文章

  1. JS中Node节点总结
  2. Spark On K8S 在有赞的实践与经验
  3. 13行代码AC_Justifying the Conjecture Gym - 102394J(解题报告)
  4. centos xampp安装mysql_在xampp上部署dvwa|centos(linux)环境
  5. linux的mysql如何删除用户_linux mysql增加用户,删除用户,以及用户权限
  6. 深入入门正则表达式(java) - 1 - 入门基础
  7. ajax中加html,向DIV中写入HTML(AJAX高手赐教)
  8. 第三百三十二节,web爬虫讲解2—Scrapy框架爬虫—Scrapy使用
  9. [android开发IDE]adt-bundle-windows-x86的一个bug:无法解析.rs文件--------rs_core.rsh file not found...
  10. pandas 调用mysql函数_pandas的连接函数concat()函数的具体使用方法
  11. concat oracle 多个字符串_12个常用的JavaScript字符串方法
  12. php mysql 简单聊天室_PHP实现最简单的聊天室应用
  13. 上海行政区划经纬度地图_高德AMAP行政区划边界及经纬度获取
  14. 高等数学——二重积分的计算方法
  15. 如果你觉得自己对 CSS 变量不熟悉,那么可以补充这个!
  16. Typora开始收费,替代品marktext
  17. Error while obtaining UI hierarchy XML file: com.android.ddmlib.
  18. upc51-种树 实现:树形dp+换跟+剪枝
  19. android 广告平台—杀毒软件是如何知道是否有广告的
  20. Edge、Chrome自定义新标签页网址

热门文章

  1. 【STM32】串口通信基本原理(超基础、详细版)
  2. EditText光标和文本选中样式自定义
  3. Modelsim仿真出现蓝线(Hiz高阻态)以及红线(x不定态)
  4. renren-vue 前端启动
  5. 收货地址中加入智能识别地址大幅改善下单体验
  6. 【C语言】C语言运算符总结
  7. 指派问题与匈牙利解法
  8. 世界上第一个程序员,居然是女神级别的人物?
  9. opporeno5可以用鸿蒙系统,买了OPPO Reno5系列 一定要试试这些功能
  10. Adb interface驱动无法安装解决方法!