题解报告——合金
题目描述
某公司加工一种由铁、铝、锡组成的合金。他们的工作很简单。首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同。然后,将每种原材料取出一定量,经过融解、混合,得到新的合金。新的合金的铁铝锡比重为用户所需要的比重。
现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重。公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金。
输入输出格式
输入格式:
第一行两个整数m和n(m, n ≤ 500),分别表示原材料种数和用户需要的合金种数。
第2到m + 1行,每行三个实数a, b, c(a, b, c ≥ 0 且 a + b + c = 1),分别表示铁铝锡在一种原材料中所占的比重。
第m + 2到m +n + 1行,每行三个实数a, b, c(a, b, c ≥ 0 且 a + b + c = 1),分别表示铁铝锡在一种用户需要的合金中
所占的比重。
输出格式:
一个整数,表示最少需要的原材料种数。若无解,则输出–1。
输入输出样例
10 10 0.1 0.2 0.7 0.2 0.3 0.5 0.3 0.4 0.3 0.4 0.5 0.1 0.5 0.1 0.4 0.6 0.2 0.2 0.7 0.3 0 0.8 0.1 0.1 0.9 0.1 0 1 0 0 0.1 0.2 0.7 0.2 0.3 0.5 0.3 0.4 0.3 0.4 0.5 0.1 0.5 0.1 0.4 0.6 0.2 0.2 0.7 0.3 0 0.8 0.1 0.1 0.9 0.1 0 1 0 0
5
【思路分析】
首先我们会发现,a+b+c的和恒为1所以说,如果我们确定了a,b 那么c就也确定了,所以我们就只用维护a,b。
然后如果我们把a,b看作是一个点的横纵坐标,我们可以推出(有点麻烦,设出a,b直线表达式,带入需要合成的点,解出等式),两个原料能合成的合金(a,b)一定是在两个点所在直线上的,如果有多条直线,那可以在组成的合金就在这些直线围成的最大二维平面中,然后这个问题就变成了一道计算几何。
我们需要找满足所有点都在其左侧的直线(找右侧也可以),然后将这些直线连起来,发现这些直线是有可能组成所有需要合金的。然后我们就在这些直线所连成的图上跑Floyd最小环,然后判断一下存不存在最小环即可。
值得注意的是,由于这些点的坐标都是小于1的,很容易出现很BUG的精度误差,所以这里我们就可以将坐标乘1000,就比较优秀了。
【代码实现】
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int N=510; 7 struct node{ 8 double x,y; 9 node(double x=0,double y=0):x(x),y(y){} 10 }have[N],need[N]; 11 node operator - (const node &a,const node &b){return node(b.x-a.x,b.y-a.y);} 12 int mp[N][N]; 13 int n,m,minn=1e9+7; 14 int cross(node a,node b){return a.x*b.y-a.y*b.x;} 15 bool judge(node a,node b,node c) 16 { 17 int cc=cross(b-a,c-a); 18 if(cc>0) return 1; 19 if(cc<0) return 0; 20 int minx=min(a.x,b.x),maxx=max(a.x,b.x),miny=min(a.y,b.y),maxy=max(a.y,b.y); 21 if(c.x<=maxx&&c.x>=minx&&c.y<=maxy&&c.y>=miny)return 1; 22 return 0; 23 } 24 void floyd() 25 { 26 for(int k=1;k<=n;k++) 27 for(int i=1;i<=n;i++) 28 for(int j=1;j<=n;j++) 29 if(mp[i][k]+mp[k][j]<mp[i][j]) 30 mp[i][j]=mp[i][k]+mp[k][j]; 31 for(int i=1;i<=n;i++) 32 for(int j=1;j<=n;j++) 33 { 34 if(i!=j&&minn>mp[i][j]+mp[j][i]) minn=mp[i][j]+mp[j][i]; 35 if(i==j&&minn>mp[i][j]) minn=mp[i][j]; 36 } 37 if(minn>n) printf("-1"); 38 else printf("%d",minn); 39 } 40 void inin() 41 { 42 double gg; 43 scanf("%d%d",&n,&m);memset(mp,0x3f,sizeof(mp)); 44 for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&have[i].x,&have[i].y,&gg),have[i].x*=1000.0,have[i].y*=1000.0; 45 for(int i=1;i<=m;i++) scanf("%lf%lf%lf",&need[i].x,&need[i].y,&gg),need[i].x*=1000.0,need[i].y*=1000.0; 46 } 47 int main() 48 { 49 inin(); 50 for(int i=1;i<=n;i++) 51 for(int j=1;j<=n;j++) 52 { 53 bool flag=1; 54 for(int k=1;k<=m;k++) 55 { 56 if(!judge(have[i],have[j],need[k])) 57 {flag=0;break;} 58 } 59 if(flag) mp[i][j]=1; 60 } 61 floyd(); 62 return 0; 63 }