[JSOI2007]合金

题目描述

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

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

没有忍住又去康了一道计算几何。。。
首先不难发现c是一个没有用的量,,,因为a+b+c=1了,所以c=1-a-b,当a,b都被满足的时候c肯定也被满足了。
所以只考虑a,b就行了。
又因为能被平面内若干个点代表的向量线性组合出的向量一定是在平面内这几个点构成的凸包内,所以题目就变成了找
最少的几个点使得它们形成的凸包包含所有需求点。

这也等价于找一条从一个点出发的回路,使得需求点都在回路上的边的左边且回路上的边数最小。
所以建个图跑个floyed就行了

#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
using namespace std;
const double eps=0.000000001;
double a,b,c;
int n,m,dis[maxn][maxn];
struct node{
    double x,y;
    
    node operator -(const node& u)const{
        return (node){x-u.x,y-u.y};
    }
}base[maxn],user[maxn];

inline int zt(double x){
    if(fabs(x)<=eps) return 0;
    return x>0?1:-1;
}

inline double pointmul(node x,node y){
    return x.x*y.x+x.y*y.y;
}

inline double Xmul(node x,node y){
    return x.x*y.y-y.x*x.y;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+m;i++){
        scanf("%lf%lf%lf",&a,&b,&c);
        if(i<=n) base[i]=(node){a,b};
        else user[i-n]=(node){a,b};
    }
    
    memset(dis,0x3f,sizeof(dis));
//    for(int i=1;i<=n;i++) dis[i][i]=0;
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            bool flag=1;
            node vec=base[j]-base[i];
            
            for(int k=1;k<=m;k++){
                double X=zt(Xmul(vec,user[k]-base[i]));
                if(X<0||(!X&&zt(pointmul(user[k]-base[i],user[k]-base[j]))>0)){
                    flag=0;
                    break;
                }
            }
            
            if(flag) dis[i][j]=1;
        }
    
    int ans=1<<30;
    for(int k=1;k<=n;k++)
        for(int j=1;j<=n;j++)
            for(int i=1;i<=n;i++) dis[j][i]=min(dis[j][i],dis[j][k]+dis[k][i]);
    for(int i=1;i<=n;i++) ans=min(ans,dis[i][i]);
    
    if(ans>n) puts("-1");
    else printf("%d
",ans);
    
    return 0;
}
 
原文地址:https://www.cnblogs.com/JYYHH/p/8390650.html