[bzoj1027][JSOI2007]合金

来自FallDream的博客,未经允许,请勿转载,谢谢。


某公司加工一种由铁、铝、锡组成的合金。他们的工作很简单。首先进口一些铁铝锡合金原材料,不同种类的
原材料中铁铝锡的比重不同。然后,将每种原材料取出一定量,经过融解、混合,得到新的合金。新的合金的铁铝
锡比重为用户所需要的比重。 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重。公司希望能
够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金。

n,m<=500

看到这道神题根本没头绪,只好看看题解。

因为三个参数加起来等于1,所以我们可以忽略第三个,用前两维表示一个平面上的点,两个材料能混合出来的材料是这两个点之间的线段,所以题目转换为求尽量少的点,使得这些点的凸包可以包住需要的材料的凸包。具体实现,如果所有需要的材料的点都在一条线段左边,那么这两个点之间连边,然后floyd求最小环。复杂度n^3

注意各种特判。如果全部都重点输出1,如果一条直线覆盖了所有的点判断一下是否都在线段上,是就输出2。最后要判断答案必须大于2.

#include<iostream>
#include<cstring>
#include<cstdio>
#define INF 1000000000
#define MN 500
#define eps 1e-8
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
 
int f[MN+5][MN+5];
int n,m;double Xmn=INF,Xmx=-INF,Ymn=INF,Ymx=-INF;
struct P{double x,y;
    P(double x=0,double y=0):x(x),y(y){}
    double operator^(P b){return x*b.y-y*b.x;}
    P operator-(P b){return P(x-b.x,y-b.y);}
}p[MN+5],q[MN+5];
 
bool check(double x1,double x2,double x3,double x4)
{
    if(x1>x2)swap(x1,x2);
    return x1<=x3&&x4<=x2;
}
 
int solve(int x,int y)
{
    int num1=0,num2=0;
    for(int i=1;i<=m;i++)
    {
        double crs=(p[y]-p[x])^(q[i]-p[x]);
        if(crs<-eps)num2++;
        if(crs>eps) num1++;
    }
    if(!num1&&!num2&&check(p[x].x,p[y].x,Xmn,Xmx)&&check(p[x].y,p[y].y,Ymn,Ymx))return -1;
    if(num1*num2)return 0;
    if(num1)return 2;
    if(num2)return 1;
    return 3;
}
 
bool special()
{
    for(int i=2;i<=n;i++)
        if(p[i].x!=p[1].x||p[i].y!=p[1].y)return 0;
    for(int i=1;i<=m;i++)
        if(q[i].x!=p[1].x||q[i].y!=p[1].y)return 0;
    return 1;
}
 
int main()
{
    n=read();m=read();double d;
    for(int i=1;i<=n;i++)
        scanf("%lf%lf%lf",&p[i].x,&p[i].y,&d);
    for(int i=1;i<=m;i++)
    {
        scanf("%lf%lf%lf",&q[i].x,&q[i].y,&d);
        Xmn=min(Xmn,q[i].x);Xmx=max(Xmx,q[i].x);
        Ymn=min(Ymn,q[i].y);Ymx=max(Ymx,q[i].y);
    }
    if(special())return 0*puts("1");
    memset(f,63,sizeof(f));
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
        {
            int res=solve(i,j);
            if(res==-1)return 0*puts("2");
            if(res&1)f[i][j]=1;
            if(res&2)f[j][i]=1;
        }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
             if(f[i][k]<=INF)
                for(int j=1;j<=n;j++)
                    f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
    int minn=INF;
    for(int i=1;i<=n;i++) minn=min(minn,f[i][i]);
    if(minn>2&&minn<INF)printf("%d
",minn);else puts("-1");
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/bzoj1027.html