zoukankan      html  css  js  c++  java
  • [BZOJ1027][JSOI2007]合金(凸包+最短路)

    [BZOJ1027][JSOI2007]合金(凸包+最短路)

    题面

    某公司加工一种由铁、铝、锡组成的合金。他们的工作很简单。首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同。然后,将每种原材料取出一定量,经过融解、混合,得到新的合金。新的合金的铁铝锡比重为用户所需要的比重。

    现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重。公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金。

    分析

    容易发现(c=1-a-b),那么就没必要考虑(c),只考虑(a,b). 我们先考虑2种合金((a_i,b_i)(a_j,b_j))混合的情况,设比例分别为(lambda,mu(lambda+mu=1)),那得到的新合金就是((lambda a_i+mu a_j,lambda b_i+mu b_j)).把((a,b))看成平面直角坐标系上的一个点(A_i),设原点为(O).那么得到的新合金为(lambda vec{OA_i}+mu vec{OA_j}). 由于(lambda+mu=1)根据向量知识可以得到,新的合金在点(A_i,A_j)的连线上。
    xl.JPG
    再考虑3种的情况.如上图,在两两相加形成的线段上任取两个点,新的合金在两点连线上。无数多的线段叠加在一起,就得到了一个三角形区域。以此类推,(n)种合金能够合成的金属对应的点在包含这(n)个点的多边形内

    那么问题变成了,选择最少的点,使得这些点构成的凸包内部含有所有需要的点。我们可以枚举可能成为凸包的线段(A_iA_j),从(i)(j)连一条边权为1的边。判断是否可能在凸包上,只需要用叉积判断是否存在点在向量(vec{A_iA_j})右侧即可,注意特判共线但不在线段上的情况。这一步的复杂度是(O(n^2m)).这样图上一个回路就对应一个凸包,Floyd求最小环即可。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring> 
    #include<cmath>
    #define maxn 500
    #define eps 1e-7
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef double db;
    struct Vector{
    	db x;
    	db y;
    	Vector(){
    		
    	}
    	Vector(db _x,db _y){
    		x=_x;
    		y=_y;
    	}
    	friend Vector operator + (Vector p,Vector q){
    		return Vector(p.x+q.x,p.y+q.y);
    	}
    	friend Vector operator - (Vector p,Vector q){
    		return Vector(p.x-q.x,p.y-q.y); 
    	}
    };
    db cross(Vector p,Vector q){
    	return p.x*q.y-p.y*q.x;
    }
    db dot(Vector p,Vector q){
    	return p.x*q.x+p.y*q.y;
    }
    inline int sgn(double x){
    	if(fabs(x)<=eps) return 0;
    	else if(x>0) return 1;
    	else return -1; 
    }
    
    int n,m;
    Vector a[maxn+5],b[maxn+5];
    int dist[maxn+5][maxn+5]; 
    bool check(int p,int q){
    	for(int i=1;i<=m;i++){
    		int f=sgn(cross(a[q]-a[p],b[i]-a[p]));
    		if(f<0) return 0;//如果有点在PQ右侧,说明一定不是凸包的边
    		if(f==0&&sgn(dot(b[i]-a[p],b[i]-a[q]))>0) return 0;//如果共线但不在线段PQ上 
    	}
    	return 1;
    }
    int floyd(){//找出包含所有b[i]的边数最少的凸包,因为有向图,直接输出dist[i][i] 
    	int ans=INF;
    	for(int k=1;k<=n;k++){ 
    		for(int i=1;i<=n;i++){
    			for(int j=1;j<=n;j++) dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
    		}
    	} 
    	for(int i=1;i<=n;i++) ans=min(ans,dist[i][i]);
    	return ans;
    }
    int main(){
    	db u,v,w;
    	scanf("%d %d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%lf %lf %lf",&u,&v,&w);
    		a[i]=Vector(u,v);
    	}	
    	for(int i=1;i<=m;i++){
    		scanf("%lf %lf %lf",&u,&v,&w);
    		b[i]=Vector(u,v);
    	}
    	memset(dist,0x3f,sizeof(dist));
    	for(int i=1;i<=n;i++){
    //		dist[i][i]=0;
    		for(int j=1;j<=n;j++){
    			//看看i->j这条边是否可能成为凸包的边 
    			if(check(i,j)){
    //				printf("%d->%d
    ",i,j);
    				dist[i][j]=1;
    			}
    		}
    	}
    //	memcpy(dist,edge,sizeof(edge));
    	int ans=floyd();
    	if(ans>n) ans=-1;
    	printf("%d
    ",ans);	
    }
    
  • 相关阅读:
    导包路径
    django导入环境变量 Please specify Django project root directory
    替换django的user模型,mysql迁移表报错 django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependen cy user.0001_initial on database 'default'.
    解决Chrome调试(debugger)
    check the manual that corresponds to your MySQL server version for the right syntax to use near 'order) values ('徐小波','XuXiaoB','男','1',' at line 1")
    MySQL命令(其三)
    MySQL操作命令(其二)
    MySQL命令(其一)
    [POJ2559]Largest Rectangle in a Histogram (栈)
    [HDU4864]Task (贪心)
  • 原文地址:https://www.cnblogs.com/birchtree/p/13573499.html
Copyright © 2011-2022 走看看