zoukankan      html  css  js  c++  java
  • 【CF666D】Chain Reaction(暴搜+细节讨论)

    点此看题面

    • 给定平面直角坐标系内四个顶点(p_i),对于每个点选择与它横坐标相同或纵坐标相同的一个点(p'_i)
    • 要求(p'_i)是一个四边平行于坐标轴的正方形的四个顶点(不能退化成一点)。
    • (max_{i=0}^3dis(p_i,p_i'))的最小值并构造一组方案。
    • 数据组数(le50)

    暴枚+初步分类讨论

    首先,我们直接暴枚对于每个(p_i)(p_i')是与它横坐标相同还是纵坐标相同,由此便可以得到四条与坐标轴平行的取点直线。

    显然,如果有超过两条相同的直线(正方形中不可能有三点某一维坐标相同)或某个方向上有超过两条不同的直线(正方形一个方向上只有两种坐标)肯定无解。

    而若去重后两个方向上都恰有一条直线,实际上这也是无解的。

    通过上面的分析,发现剩余的情况必然有至少一个方向上恰有两条不同的直线,则正方形的边长(d)就固定为这两直线间距离。

    不妨假设是有两条与(x)轴平行的直线,那么只需分三类讨论就行了。

    (2+2)

    显然交点必选,只要判断组成的是不是正方形即可。

    注意,这里有一个偷懒的写法,求出正方形的一种顶点方案后,我们不用直接判断谁与谁配对,而可以写个全排列暴搜,这样可以省去不少细节。这在之后的情况中也同样适用。

    (2+1)

    同理两个交点必选,然后正方形就只有左右两个。

    两种情况分别搜一下就好了。

    (2+0)

    相当于可以任选一个夹在这两条直线之间的正方形。

    对于一条直线上两点,肯定让正方形左边的点和左边的点配对,正方形右边的点和右边的点配对。

    假设正方形左边的横坐标为(t),那么右边横坐标就是(t+d)

    到左边(x_L)的距离就是(|t-x_L|),而到右边(x_R)的距离就是(|t+d-x_R|=|t-(x_R-d)|)

    所以我们只要把两条直线上的(x_L,x_R-d)放在一起求出最小值和最大值,那么(t)的最优取值就是它俩的平均数。

    代码:(O(Tcdot2^4cdot4!))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    using namespace std;
    int ans,x[4],y[4],sx[4],sy[4],gx[4],gy[4],ox[4],oy[4],id[9];map<int,int> cx,cy;
    int u[4];I void Match(CI i=0,CI t=0)//全排列暴搜匹配方式
    {
    	if(t>=ans) return;if(i==4) {for(RI j=0;j^4;++j) sx[j]=ox[j],sy[j]=oy[j];return (void)(ans=t);}
    	for(RI j=0;j^4;++j) !u[j]&&(u[j]=1,ox[j]=gx[i],oy[j]=gy[i],
    		(x[j]==gx[i]||y[j]==gy[i])&&(Match(i+1,max(t,abs(x[j]-gx[i])+abs(y[j]-gy[i]))),0),u[j]=0);//至少有一维相同
    }
    int kx[2],ky[2];I void dfs(CI i,RI tx=0,RI ty=0)//暴枚每个点哪维相同
    {
    	#define T(x) (id[x&-x])//状压的第一个点编号
    	#define P(x) (id[x^(x&-x)])//状压的第二个点编号
    	#define Work(x0,y0,x1,y1,x2,y2,x3,y3) (gx[0]=x0,gy[0]=y0,gx[1]=x1,gy[1]=y1,gx[2]=x2,gy[2]=y2,gx[3]=x3,gy[3]=y3,Match())//根据一组顶点方案开始搜索
    	if(i==4)//暴枚完了
    	{
    		RI d;if(tx==1&&ty==1) return;if(tx==2&&ty==2)//1+1(无解);2+2
    		{
    			abs(kx[0]-kx[1])==abs(ky[0]-ky[1])&&(Work(kx[0],ky[0],kx[0],ky[1],kx[1],ky[0],kx[1],ky[1]),0);return;//如果是正方形就去搜
    		}
    		if(ty==1) return d=abs(kx[0]-kx[1]),//1+2
    			Work(kx[0],ky[0],kx[1],ky[0],kx[0],ky[0]+d,kx[1],ky[0]+d),Work(kx[0],ky[0],kx[1],ky[0],kx[0],ky[0]-d,kx[1],ky[0]-d);//上下两个
    		if(tx==1) return d=abs(ky[0]-ky[1]),//2+1
    			Work(kx[0],ky[0],kx[0],ky[1],kx[0]+d,ky[0],kx[0]+d,ky[1]),Work(kx[0],ky[0],kx[0],ky[1],kx[0]-d,ky[0],kx[0]-d,ky[1]);//左右两个
    		if(!ty)//0+2
    		{
    			int tmp[4]={y[T(cx[kx[0]])],y[P(cx[kx[0]])],y[T(cx[kx[1]])],y[P(cx[kx[1]])]};
    			tmp[0]>tmp[1]&&(swap(tmp[0],tmp[1]),0),tmp[2]>tmp[3]&&(swap(tmp[2],tmp[3]),0),
    			d=abs(kx[0]-kx[1]),tmp[1]-=d,tmp[3]-=d,sort(tmp,tmp+4);RI t=tmp[0]+tmp[3]>>1;//取最小值和最大值的平均数
    			return Work(kx[0],t,kx[1],t,kx[0],t+d,kx[1],t+d);
    		}
    		if(!tx)//2+0
    		{
    			int tmp[4]={x[T(cy[ky[0]])],x[P(cy[ky[0]])],x[T(cy[ky[1]])],x[P(cy[ky[1]])]};
    			tmp[0]>tmp[1]&&(swap(tmp[0],tmp[1]),0),tmp[2]>tmp[3]&&(swap(tmp[2],tmp[3]),0),
    			d=abs(ky[0]-ky[1]),tmp[1]-=d,tmp[3]-=d,sort(tmp,tmp+4);RI t=tmp[0]+tmp[3]>>1;//取最小值和最大值的平均数
    			return Work(t,ky[0],t,ky[1],t+d,ky[0],t+d,ky[1]);
    		}
    	}
    	if(!P(cx[x[i]])&&(cx[x[i]]||tx^2)) !cx[x[i]]&&(kx[tx++]=x[i]),cx[x[i]]^=1<<i,dfs(i+1,tx,ty),!(cx[x[i]]^=1<<i)&&--tx;//不能有超过两条重合,同向不能超过两条不同
    	if(!P(cy[y[i]])&&(cy[y[i]]||ty^2)) !cy[y[i]]&&(ky[ty++]=y[i]),cy[y[i]]^=1<<i,dfs(i+1,tx,ty),!(cy[y[i]]^=1<<i)&&--ty;//不能有超过两条重合,同向不能超过两条不同
    }
    int main()
    {
    	RI Tt,i;for(scanf("%d",&Tt),i=0;i^4;++i) id[1<<i]=i;W(Tt--)
    	{
    		for(i=0;i^4;++i) scanf("%d%d",x+i,y+i);if(ans=1e9,dfs(0),ans==1e9) {puts("-1");continue;};
    		for(printf("%d
    ",ans),i=0;i^4;++i) printf("%d %d
    ",sx[i],sy[i]);
    	}return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    2-6 求阶乘序列前N项和
    2-5 求平方根序列前N项和
    2-4 求交错序列前N项和
    2-3 求平方与倒数序列的部分和
    2-2 阶梯电价
    2-1 求整数均值
    2-17 生成3的乘方表
    【秋招之行】自白篇
    Django开发个人博客入门学习经验贴
    浅尝装饰器和AOP
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF666D.html
Copyright © 2011-2022 走看看