• 「JSOI2007」合金


    JSOI2007 合金

    题意

    \(~~~~\) 给出 \((n+m)\) 个三维点,满足坐标和为 \(1\) 。要求从前 \(n\) 个点中选最少的围成一个多边形,使得后 \(m\) 个多边形均在该多边形内部或边上。求最少选择的数量。

    \(~~~~\) \(1\leq n,m\leq 500\).

    废话

    \(~~~~\) 考场上用 \(20\min\) 胡出来了跟讨论区这一篇完全一样的东西,但甚至没打出来。

    题解

    \(~~~~\) 首先由于这些点的坐标和为 \(1\) ,那么它们都在同一平面内,因此把它们都改为这一平面上的二维点。(事实上保留前两维即可原因同上,如果数据强一点可能这样还会掉精度)

    \(~~~~\) 考虑什么样的点是可以选的,我们发现如果两个点它们之间的连线使得所有目标点都在这条线段的同侧或之上,那么这样的两个点之间可以选来作为最终多边形的一条边。

    \(~~~~\) 考虑最后我们要求的多边形事实上就是选择最少得边使其成环,且边满足上述条件,故通过上面的条件建图然后跑出最小环即可。数据范围不大,故可以使用 Floyd

    代码

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    struct Point{
    	double x,y,ang;
    	Point(){}
    	Point(double X,double Y){x=X,y=Y;}
    	Point operator +(const Point ano){return Point(x+ano.x,y+ano.y);}
    	Point operator -(const Point ano){return Point(x-ano.x,y-ano.y);}
    	Point operator *(const double k) {return Point(x*k,y*k);}
    	double operator *(const Point ano){return x*ano.x+y*ano.y;}
    	double operator ^(const Point ano){return x*ano.y-y*ano.x;}
    }P1[505],P2[505]; 
    const double EPS=1e-5;
    double Dis(Point a,Point b){return sqrt((a.y-b.y)*(a.y-b.y)+(a.x-b.x)*(a.x-b.x));}
    double GetDis(double x,double y,double z){return sqrt((x+y-1)*(x+y-1)/2+z*z);}
    double Fabs(double x){return x>=EPS?x:-x;}
    double Sign(double x)
    {
    	if(Fabs(x)<=EPS) return 0;
    	else return Fabs(x)/x;
    }
    bool cmp(Point x,Point y){return x.ang!=y.ang?x.ang<y.ang:Dis(x,P1[1])<Dis(y,P1[1]);}
    int n,m,Sta[505],Top;
    int dis[505][505];
    bool CanLink(Point A,Point B)
    {
    	for(int i=1;i<=m;i++)
    	{
    		double Tmp;
    		Tmp=(P2[i]-A)^(B-A);
    		if(Tmp<-EPS) return false;
    		if(Fabs(Tmp)<EPS&&(max(A.x,B.x)<P2[i].x||P2[i].x<min(A.x,B.x))) return false;
    	}
    	return true;
    }
    int main() {
    	double x,y,z;
    	scanf("%d %d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%lf %lf %lf",&x,&y,&z);
    		P1[i].x=GetDis(y,z,x); P1[i].y=GetDis(x,y,z);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%lf %lf %lf",&x,&y,&z);
    		P2[i].x=GetDis(y,z,x); P2[i].y=GetDis(x,y,z);
    	}
    	if(n==1)
    	{
    		for(int i=1;i<=m;i++) if(P1[1].x!=P2[i].x||P1[1].y!=P2[i].y) return puts("-1")&0;
    		puts("1");
    		return 0;
    	}
    	memset(dis,0x3f,sizeof(dis));
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			if(i==j) continue;
    			if(CanLink(P1[i],P1[j])) dis[i][j]=1;
    		}
    	}
    	int Ans=1e8;
    	for(int k=1;k<=n;k++)
    	{
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++) 
    				dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
    	}
    	for(int i=1;i<=n;i++) Ans=min(Ans,dis[i][i]);
    	if(Ans==1e8) Ans=-1;
    	printf("%d",Ans);
    	return 0;
    }
    

    \(~~~~\)

  • 相关阅读:
    WPF控件操作之改变父控件之TabControl示例
    WPF里面的DockPanel的Fill去哪了,如何填满整个空间
    [原创]winform自定义控件之类属性-多重属性-可折叠属性
    WinForm之DataBinding
    WinForm自定义控件之DefaultValue的误解
    code snippet:依赖属性propa的小技巧
    【原创】WinForm中实现单独Time控件的方式
    node.js安装本地模块遇到的目录锁定问题【新手问题】
    《程序员思维修炼》之德雷福斯模型
    IOptions、IOptionsMonitor以及IOptionsSnapshot
  • 原文地址:https://www.cnblogs.com/Azazel/p/15866527.html
Copyright © 2020-2023  润新知