• CF1045E Ancient civilizations


    XV.CF1045E Ancient civilizations

    神题。

    我们先考虑如果凸包上只有三个点时的情形。

    假如该三个点是同色的,我们考虑能否在该三角形内部找到一个异色点。假如能找到,我们便可以将这个大三角形拆分成三个小三角形,每个小三角形以该异色节点和凸包上两个点为顶点,这就使得小三角形的三个顶点并不同色。这样我们就可以递归到下一种情形了。假如找不到,则明显该三角形内部所有点全部同色,直接从一个点出发连接所有点即可。

    下面我们考虑三个点不全同色的情形。则必定有一个少数色。我们便在三角形内部寻找有无少数色的节点。假如有的话,明显我们可以连接该少数色节点和少数色的顶点,然后继续拆分成三个小三角形继续递归处理。假如没有,就直接暴力连即可。

    下面我们考虑一般情况,即凸包上不只有三个点的情形。我们考虑将该凸包拆成一段黑一段白这样交替出现的情形。假如有两段颜色相同的凸包上节点并不相邻,明显无论怎么连都会出现交叉,直接跳无解。否则:

    假如凸包上只有一种颜色的点,明显可以如三角形三点同色一样,剖分成数个小三角形进行处理。否则,即凸包上不止有一种颜色的点,那么我们找到凸包上白点中最左的那一个(指按照顺/逆时针排序后白点段中最靠左的那个),连接其和所有黑点构成三角形(并非真的相连,只是指构成三角形罢了);同理,找到黑点中最靠左的那个,并连接其和所有白点构成三角形。明显此时我们便将整个大凸包拆成了无数的异色三角形,可以递归处理了。

    明显在每次递归处理中,我们都要一遍扫过所有节点判断它是否在三角形内部,故总复杂度\(O(n^2)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,stk[1010],tp,ord[1010];
    struct Vector{
    	int x,y;
    	Vector(int X=0,int Y=0){x=X,y=Y;}
    	friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
    	friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
    	friend int operator &(const Vector &u,const Vector &v){return u.x*v.y-u.y*v.x;}//cross times
    	friend int operator |(const Vector &u,const Vector &v){return u.x*v.x+u.y*v.y;}//point times
    	double operator ~()const{return atan2(y,x);}
    	void read(){scanf("%d%d",&x,&y);}
    	void print(){printf("(%d,%d)",x,y);}
    }p[1010];
    bool col[1010];
    vector<pair<int,int> >edges;
    void solve(int u,int v,int w){
    	bool minor=col[u]^col[v]^col[w];
    	int MINOR;
    	if(col[u]==minor)MINOR=u;
    	if(col[v]==minor)MINOR=v;
    	if(col[w]==minor)MINOR=w;
    	for(int i=0;i<n;i++){
    		if(i==u||i==v||i==w)continue;
    		if(col[i]!=minor)continue;
    		bool U=((p[u]-p[i])&(p[v]-p[i]))>0;
    		bool V=((p[v]-p[i])&(p[w]-p[i]))>0;
    		bool W=((p[w]-p[i])&(p[u]-p[i]))>0;
    		if(U!=V||V!=W||W!=U)continue;
    		edges.push_back(make_pair(MINOR,i));
    		solve(u,v,i),solve(v,w,i),solve(w,u,i);
    		return;
    	}
    	for(int i=0;i<n;i++){
    		if(i==u||i==v||i==w)continue;
    		bool U=((p[u]-p[i])&(p[v]-p[i]))>0;
    		bool V=((p[v]-p[i])&(p[w]-p[i]))>0;
    		bool W=((p[w]-p[i])&(p[u]-p[i]))>0;
    		if(U!=V||V!=W||W!=U)continue;
    		if(col[u]==col[i]){edges.push_back(make_pair(u,i));continue;}
    		if(col[v]==col[i]){edges.push_back(make_pair(v,i));continue;}
    		if(col[w]==col[i]){edges.push_back(make_pair(w,i));continue;}
    	}
    }
    bool onhull[1010];
    void print(){
    	printf("%d\n",edges.size());
    	for(auto i:edges)printf("%d %d\n",i.first,i.second);
    	exit(0);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=0;i<n;i++)p[i].read(),scanf("%d",&col[i]),ord[i]=i;
    	sort(ord,ord+n,[](int u,int v){return p[u].x==p[v].x?p[u].y<p[v].y:p[u].x<p[v].x;});
    	for(int i=1;i<n;i++)p[ord[i]]=p[ord[i]]-p[ord[0]];
    	p[ord[0]]=Vector(0,0);
    	sort(ord+1,ord+n,[](int u,int v){return ~p[u]<~p[v];});
    	stk[tp++]=ord[0];
    	for(int i=1;i<n;i++){
    		while(tp>=2&&((p[ord[i]]-p[stk[tp-1]])&(p[stk[tp-1]]-p[stk[tp-2]]))>=0)tp--;
    		stk[tp++]=ord[i];
    	}
    	for(int i=0;i<tp;i++)onhull[stk[i]]=true;
    	int l=tp,r=1;
    	while(r<l&&col[stk[r]]==col[stk[0]])r++;
    	while(l>r&&col[stk[l-1]]==col[stk[0]])l--;
    	if(r==l){
    		for(int j=1;j<tp;j++)edges.push_back(make_pair(stk[j-1],stk[j]));
    		for(int i=0;i<n;i++){
    			if(onhull[i]||col[i]==col[stk[0]])continue;
    			for(int j=0;j<tp;j++)solve(stk[j],stk[(j+1)%tp],i);
    			print();
    		}
    		for(int i=0;i<n;i++){
    			if(onhull[i])continue;
    			for(int j=i+1;j<n;j++)if(!onhull[j])edges.push_back(make_pair(i,j));
    			if(col[i]==col[stk[0]])edges.push_back(make_pair(i,stk[0]));
    			print();
    		}
    	}else{
    		for(int i=r;i<l;i++)if(col[stk[i]]==col[stk[0]]){puts("Impossible");return 0;}
    		for(int i=(l+1)%tp;i!=r;i=(i+1)%tp)edges.push_back(make_pair(stk[(i+tp-1)%tp],stk[i]));
    		for(int i=r+1;i<l;i++)edges.push_back(make_pair(stk[i-1],stk[i]));
    		for(int i=(l+1)%tp;i!=r;i=(i+1)%tp)solve(stk[(i+tp-1)%tp],stk[i],stk[r]);
    		for(int i=r+1;i<l;i++)solve(stk[i-1],stk[i],stk[l%tp]);
    		print();
    	}
    	print();
    	return 0;
    }
    

  • 相关阅读:
    windows任务计划
    PHP创建多级文件夹
    js正则表达式(不断总结中....)
    js随机改变背景颜色
    提高PHP代码质量36计
    PHP中使用Filter进行数据安全过滤
    CSS颜色代码大全
    正则表达式的修饰符
    创建索引视图
    读取xml中的所有文件名
  • 原文地址:https://www.cnblogs.com/Troverld/p/14619354.html
Copyright © 2020-2023  润新知