zoukankan      html  css  js  c++  java
  • P4049 [JSOI2007]合金

    题意

    因为(a+b+c=1),因此只要知道(a,b),就可以知道(c)。也就是说只用(a,b)即可表示出一种材料/合金,我们将每种材料/合金表示为坐标系上的

    一种材料(a)能表示出的合金为(a)
    两种材料(a,b)能表示出的合金为线段(ab)上的所有点。
    三种材料(a,b,c)能表示出的合金为(ab,bc,ac)围成的三角形中所有的点。
    推广可得:(k)种材料能表示出的合金为这(k)个点的凸包内的所有点。

    我们枚举每一对材料((i,j)),满足所有需求点都在线段(ij)一边,之后根据在哪边连边,之后跑最小环即可。

    注意特判只有重点和共线的情况。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    const int maxn=510;
    const double eps=1e-8;
    const int inf=0x3f3f3f3f;
    int n,m,ans=inf;
    int dis[maxn][maxn];
    double xmin=inf,xmax=-inf,ymin=inf,ymax=-inf;
    struct Point
    {
        double x,y;
        inline double len(){return sqrt(x*x+y*y);}
        Point operator+(const Point a)const{return (Point){x+a.x,y+a.y};}
        Point operator-(const Point a)const{return (Point){x-a.x,y-a.y};}
        Point operator*(const double k){return (Point){x*k,y*k};}
        Point operator/(const double k){return (Point){x/k,y/k};}
        double operator*(const Point a)const{return x*a.y-y*a.x;}
        double operator&(const Point a)const{return x*a.x+y*a.y;}
    }p1[maxn],p2[maxn];
    inline int dcmp(double x)
    {
    	if(fabs(x)<=eps)return 0;
    	return x<0?-1:1;
    }
    inline bool check(double x1,double x2,double x3,double x4)
    {
    	if(dcmp(x1-x2)>0)swap(x1,x2);
    	return dcmp(x1-x3)<=0&&dcmp(x4-x2)<=0;
    }
    inline void solve(int x,int y)
    {
    	int cnt1=0,cnt2=0;
    	for(re int i=1;i<=m;i++)
    	{
    		double tmp=(p1[y]-p1[x])*(p2[i]-p1[x]);
    		if(dcmp(tmp)<0)cnt1++;
    		if(dcmp(tmp)>0)cnt2++;
    	} 
    	if(!cnt1&&!cnt2&&check(p1[x].x,p1[y].x,xmin,xmax)&&check(p1[x].y,p1[y].y,ymin,ymax)){puts("2");exit(0);}//共线。 
    	if(cnt1&&cnt2)return;
    	if(cnt1)dis[x][y]=1;
    	if(cnt2)dis[y][x]=1;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	double tmp;
    	for(re int i=1;i<=n;i++)scanf("%lf%lf%lf",&p1[i].x,&p1[i].y,&tmp);
    	for(re int i=1;i<=m;i++)
    	{
    		scanf("%lf%lf%lf",&p2[i].x,&p2[i].y,&tmp);
    		xmin=min(xmin,p2[i].x),xmax=max(xmax,p2[i].x);
    		ymin=min(ymin,p2[i].y),ymax=max(ymax,p2[i].y);
    	}
    	bool flag=1;
    	for(re int i=1;i<=n;i++)if(dcmp(p1[i].x-p1[1].x)!=0||dcmp(p1[i].y-p1[1].y)!=0)flag=0;
    	for(re int i=1;i<=n;i++)if(dcmp(p2[i].x-p2[1].x)!=0||dcmp(p2[i].y-p2[1].y)!=0)flag=0;
    	if(flag){puts("1");return 0;}//重点。 
    	memset(dis,0x3f,sizeof(dis));
    	for(re int i=1;i<=n;i++)
    		for(re int j=i+1;j<=n;j++)
    			solve(i,j);
    	for(re int k=1;k<=n;k++)
    		for(re int i=1;i<=n;i++)
    		{
    			if(dis[i][k]==inf)continue;
    			for(re int j=1;j<=n;j++)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    		}
    	for(re int i=1;i<=n;i++)ans=min(ans,dis[i][i]);
    	if(ans==inf||ans<2)puts("-1");
    	else printf("%d",ans);
    	return 0;
    } 
    
  • 相关阅读:
    深入理解递归函数的调用过程
    关于字符串和字符数组的再讨论
    返回字符串的长度
    再写静态变量的有效范围
    一道关于返回指针和返回数组名的面试题
    关于TCP/IP的三次握手和四次挥手解释
    C++面向对象的编程(二)
    关于面试宝典中的检测并修改不适合的继承
    argc和argv
    基于C的文件操作(转)
  • 原文地址:https://www.cnblogs.com/nofind/p/12212509.html
Copyright © 2011-2022 走看看