• 题解报告——合金


    题目传送门

    题目描述

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

    现在,用户给出了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。

    输入输出样例

    输入样例#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
    输出样例#1: 复制
    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 }
  • 相关阅读:
    全程软件测试_项目启动
    全程软件测试_规范测试过程
    python_json常用的方法
    python_eval的用法
    python_判断字符串编码的方法
    python_Notepad++编码集的说明
    python_编码集的介绍
    初识HTML
    mysql学习目录
    python学习目录
  • 原文地址:https://www.cnblogs.com/genius777/p/9215237.html
Copyright © 2020-2023  润新知