原文链接https://www.cnblogs.com/zhouzhendong/p/CF1045E.html

4K码量构造题,CF血腥残暴!

题解

首先,如果所有点颜色相同,那么直接连个菊花搞定。

然后我们建个凸包。

如果凸包上有大于2段颜色(就是至少四段),比如这样

那么必然无解。

否则就只有一段颜色或者两段颜色:

这里我们先不管这个,考虑一个三角形的构造。

考虑三角形三个顶点颜色不全相同的情况,例如:

(两个白点的情况是等价的)

假如三角形区域内没有白点,那么直接全部连到其中一个黑点就好了。

否则假设里面有一个白点:

那么我们将白顶点连上这个中间的白点(将红色边加入最终答案),把原三角形划分成3个子问题递归求解即可。

回到原问题:

如果凸包上只有一种颜色,那么在里面找一个白点(因为已经排除全部都是黑点的情况了,所以必然有白点),如下图一样将红色边相连,按照红/黑色边将凸包三角划分成子问题解决即可:

如果凸包上有两种颜色,那么就类似地:

划分集合的暴力枚举点判定是否在三角形内就好了。

代码

#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
using namespace std;
typedef long long LL;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=1005;
int n;
struct Point{
int x,y;
Point(){}
Point(int _x,int _y){
x=_x,y=_y;
}
friend Point operator + (Point A,Point B){
return Point(A.x+B.x,A.y+B.y);
}
friend Point operator - (Point A,Point B){
return Point(A.x-B.x,A.y-B.y);
}
friend bool operator == (Point A,Point B){
return A.x==B.x&&A.y==B.y;
}
friend bool operator != (Point A,Point B){
return A.x!=B.x||A.y!=B.y;
}
}O;
int cross(Point A,Point B){
return A.x*B.y-B.x*A.y;
}
int cross(Point A,Point B,Point C){
return cross(B-A,C-A);
}
int Dot(Point A,Point B){
return A.x*B.x+A.y*B.y;
}
int Dis(Point A,Point B){
return Dot(A-B,A-B);
}
struct civ{
Point p;
int c,id;
civ(){}
civ(Point _p,int _c,int _id){
p=_p,c=_c,id=_id;
}
};
civ Get_civ(int id){
Point p;
p.x=read(),p.y=read();
int c=read();
return civ(p,c,id);
}
vector <civ> p,con;
bool cmpO(Point a,Point b){
return a.y!=b.y?a.y<b.y:a.x<b.x;
}
bool cmpAngle_civ(civ a,civ b){
int c=cross(O,a.p,b.p);
return c?c>0:Dis(O,a.p)<Dis(O,b.p);
}
vector <civ> Get_Convex(vector <civ> p){
vector <civ> st(0);
int n=p.size();
for (int i=1;i<n;i++)
if (!cmpO(p[0].p,p[i].p))
swap(p[0],p[i]);
O=p[0].p;
sort(p.begin()+1,p.end(),cmpAngle_civ);
for (int i=0;i<n;i++){
while (st.size()>1&&cross(st[st.size()-2].p,st.back().p,p[i].p)<=0)
st.pop_back();
st.push_back(p[i]);
}
return st;
}
int check_same(){
for (int i=1;i<n;i++)
if (p[i].c!=p[0].c)
return 0;
return 1;
}
int check_inside(Point A,Point B,Point C,Point P){
if (P==A||P==B||P==C)
return 0;
int S1=abs(cross(A,B,C));
int S2=abs(cross(P,A,B))+abs(cross(P,B,C))+abs(cross(P,C,A));
return S1==S2;
}
vector <civ> get_inside(Point A,Point B,Point C,vector <civ> S){
static vector <civ> res;
res.clear();
for (auto v : S)
if (check_inside(A,B,C,v.p))
res.push_back(v);
return res;
}
vector <pair <int,int> > ans;
void solve(civ A,civ B,civ C,vector <civ> S){
int flag=0;
civ p;
for (auto c : S)
if (c.c!=A.c){
flag=1,p=c;
break;
}
if (!flag){
for (auto c : S)
ans.push_back(make_pair(A.id,c.id));
return;
}
ans.push_back(make_pair(C.id,p.id));
solve(A,B,p,get_inside(A.p,B.p,p.p,S));
solve(C,p,A,get_inside(C.p,p.p,A.p,S));
solve(C,p,B,get_inside(C.p,p.p,B.p,S));
}
int main(){
n=read();
for (int i=1;i<=n;i++)
p.push_back(Get_civ(i));
con=Get_Convex(p);
int cnt=con[0].c^con.back().c;
for (int i=1;i<con.size();i++)
cnt+=con[i-1].c^con[i].c;
if (cnt>2)
return puts("Impossible"),0;
ans.clear();
if (cnt==0){
if (check_same()){
printf("%d\n",n-1);
for (int i=1;i<n;i++)
printf("%d %d\n",0,i);
return 0;
}
for (int i=1;i<con.size();i++)
ans.push_back(make_pair(con[i-1].id,con[i].id));
civ mid;
for (auto c : p)
if (c.c!=con[0].c){
mid=c;
break;
}
solve(con[0],con.back(),mid,get_inside(con[0].p,con.back().p,mid.p,p));
for (int i=1;i<con.size();i++)
solve(con[i-1],con[i],mid,get_inside(con[i-1].p,con[i].p,mid.p,p));
}
else {
vector <civ> _con(0);
int stco=con[0].c^1,i;
int m=con.size();
for (i=0;;i=(i+1)%m)
if (con[i].c==stco){
_con.push_back(con[i]);
if (con[(i+1)%m].c!=stco)
break;
}
stco^=1;
for (i=(i+1)%m;;i=(i+1)%m)
if (con[i].c==stco){
_con.push_back(con[i]);
if (con[(i+1)%m].c!=stco)
break;
}
con=_con;
for (i=0;i<m;i++)
if (con[i].c!=con[(i+1)%m].c)
break;
int b=i;
for (int i=0;i<b;i++)
ans.push_back(make_pair(con[i].id,con[i+1].id));
for (int i=b+1;i<m-1;i++)
ans.push_back(make_pair(con[i].id,con[i+1].id));
b++;
for (int i=0;i<b-1;i++)
solve(con[i],con[i+1],con[b],get_inside(con[i].p,con[i+1].p,con[b].p,p));
for (int i=b;i<m-1;i++)
solve(con[i],con[i+1],con[0],get_inside(con[i].p,con[i+1].p,con[0].p,p));
}
printf("%d\n",(int)ans.size());
for (auto e : ans)
printf("%d %d\n",e.first-1,e.second-1);
return 0;
}

  

Codeforces 1045E. Ancient civilizations 构造 计算几何 凸包的更多相关文章

  1. Codeforces Beta Round #1 C. Ancient Berland Circus 计算几何

    C. Ancient Berland Circus 题目连接: http://www.codeforces.com/contest/1/problem/C Description Nowadays a ...

  2. Codeforces Gym100543B 计算几何 凸包 线段树 二分/三分 卡常

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF-Gym100543B.html 题目传送门 - CF-Gym100543B 题意 给定一个折线图,对于每一条 ...

  3. 计算几何---凸包问题(Graham/Andrew Scan )

    概念 凸包(Convex Hull)是一个计算几何(图形学)中的概念.用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有点的.严谨的定义和相关概念参 ...

  4. 计算几何-凸包-toleft test

    toLeftTest toLeftTest是判断一个点是否在有向直线左侧的算法. 当点s位于向量pq左侧时,toLeftTest返回true.当点s位于向量pq右侧时,toLeftTest返回fals ...

  5. 计算几何-凸包算法 Python实现与Matlab动画演示

    凸包算法是计算几何中的最经典问题之一了.给定一个点集,计算其凸包.凸包是什么就不罗嗦了 本文给出了<计算几何——算法与应用>中一书所列凸包算法的Python实现和Matlab实现,并给出了 ...

  6. Codeforces 1383D - Rearrange(构造)

    Codeforces 题面传送门 & 洛谷题面传送门 一道不算困难的构造,花了一节英语课把它搞出来了,题解简单写写吧( 考虑从大往小加数,显然第三个条件可以被翻译为,每次加入一个元素,如果它所 ...

  7. Codeforces 549B. Looksery Party[构造]

    B. Looksery Party time limit per test 1 second memory limit per test 256 megabytes input standard in ...

  8. 【BZOJ-1069】最大土地面积 计算几何 + 凸包 + 旋转卡壳

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 2707  Solved: 1053[Submit][Sta ...

  9. codeforces 323A. Black-and-White Cube 构造

    输入n 1 <= n <= 100 有一个n * n * n 的立方体,由n ^ 3 个1 * 1 * 1 的单位立方体构成 要用white 和 black 2种颜色来染这n ^ 3个立方 ...

随机推荐

  1. Qt QWidget

    原文: https://www.cnblogs.com/muyuhu/archive/2012/10/26/2741184.html QWidget 类代表一般的窗口,其他窗口类都是从 QWidget ...

  2. 2.3 os 模块

    目录 2.3.1 功能 2.3.2 常用方法 2.3.2.1 创建相关 2.3.2.2 切换相关 2.3.2.3 查看相关 2.3.2.4 编辑相关 2.3.2.5 删除相关 2.3.1 功能 2.3 ...

  3. JVM运行时内存组成分为一些线程私

    JVM运行时内存组成分为一些线程私有的,其他的是线程共享的. 线程私有 程序计数器:当前线程所执行的字节码的行号指示器. Java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧 ...

  4. emwin 之 LISTWVIEW 控件禁止列滑动

    @2019-02-25 [小记] hHeader = LISTVIEW_GetHeader(hListView); WM_DisableWindow(hHeader);

  5. linux18.04+jdk11.0.2+hadoop3.1.2部署伪分布式

    1. 下载 安装hadoop3.1.2http://mirror.bit.edu.cn/apache/hadoop/common/hadoop-3.1.2/hadoop-3.1.2.tar.gz 注意 ...

  6. <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>

    <%String path = request.getContextPath();String basePath = request.getScheme()+"://"+re ...

  7. 一个select元素自定义设计的新思路:appearance: none之后利用<>符号制造小箭头

    最近工作时解决了一个前端小问题(如下图所示):在Safari中,select的控件之上有不和谐的灰色部分. 刚开始时我以为是backgrand或是border设置不当之类产生的问题,在搜索了很久之后终 ...

  8. TCP和UDP

    目录: TCP流式协议 TCP模板 TCP聊天室 TCP通信与连接循环 TCP粘包 socketserver实现并发 UDP数据报协议 UDP模板 UDP传输 socketserver实现并发 TCP ...

  9. 高并发秒杀系统--Service事务管理与继承测试

    [Spring IoC的类型及应用场景]  [Spring事务使用方式] [Spring事务的特性] [Spring事务回滚的理解] [Service声明式事务的配置] 1.配置事务管理器 2.配置基 ...

  10. go语言学习 一

    1.变量声明 指定变量类型,声明后若不赋值,使用默认值 根据值自行判定变量类型. 省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误 2.go语言作用域 函数内定义的变量称为局 ...