原文链接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. 在Django中使用logging模块

    一.Django logging配置 1.在setting.py中配置 # 日志文件存放路径 BASE_LOG_DIR = os.path.join(BASE_DIR, "log" ...

  2. linux 安装所有软件可以使用这个网站搜索RPM包

    #很方便很实用  强烈推荐 https://pkgs.org/

  3. BZOJ4671异或图

    题目描述 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 ...

  4. python之shelve模块详解

    一.定义 Shelve是对象持久化保存方法,将对象保存到文件里面,缺省(即默认)的数据存储文件是二进制的. 二.用途 可以作为一个简单的数据存储方案. 三.用法 使用时,只需要使用open函数获取一个 ...

  5. elk中fliebeat的配置文件

    fliebeat----> kafka的配置文件 # cat filebeat.yml|egrep -v "^$|^#"|grep -v "^ #" fi ...

  6. CMDB资产管理系统开发【day25】:需求分析

    本节内容 浅谈ITIL CMDB介绍 Django自定义用户认证 Restful 规范 资产管理功能开发 浅谈ITIL TIL即IT基础架构库(Information Technology Infra ...

  7. docker 安装入门

    install docker 命令 docker version // docker 版本 docker pull nginx // 拉取nginx docker images // 查看本机dock ...

  8. JN_0006:MongoDB未授权访问漏洞处理

    开启MongoDB服务时不添加任何参数时,默认是没有权限验证的,登录的用户可以通过默认端口无需密码对数据库任意操作而且可以远程访问数据库. 2.[修复建议]:临时方案:配置AUTH,做好访问认证.打开 ...

  9. vue构造函数(根实例化时和组件实例对象选项)参数:选项详解

    实例选项(即传给构造函数的options):数据,DOM,生命周期钩子函数,资源,组合,其他 数据 data 属性能够响应数据变化,当这些数据改变时,视图会进行重渲染. 访问方式: 1.通过 vm.$ ...

  10. JAVA进阶11

    间歇性混吃等死,持续性踌躇满志系列-------------第11天 1.ArrayList package cn.intcast.demo11; import java.util.ArrayList ...