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;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Poj 1742 Coins(多重背包)
    Poj 2350 Above Average(精度控制)
    求二进制数中1的个数
    Poj 1659 Distance on Chessboard(国际象棋的走子规则)
    Poj 2411 Mondriaan's Dream(压缩矩阵DP)
    Poj 2136 Vertical Histogram(打印垂直直方图)
    Poj 1401 Factorial(计算N!尾数0的个数——质因数分解)
    poj 2390 Bank Interest(计算本利和)
    Poj 2533 Longest Ordered Subsequence(LIS)
    Poj 1887 Testing the CATCHER(LIS)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF666D.html
Copyright © 2011-2022 走看看