• [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;
    }
  • 相关阅读:
    SpringMVC:拦截器拦截时机和原理
    SpringBoot:MessageConverter自动配置原理
    SpringMVC:返回值处理器原理和MessageConverter原理
    SpringMVC:自定义Converter
    XML-RPC协议学习
    ContentControl 与 ViewModel (一)
    C# 获取相对路径(绝对路径转相对路径)
    WPF 最简单的TextBox水印
    WPF/Silverlight开发的15个最佳实践(转发)
    WPF 打印崩溃问题( 异常:Illegal characters in path/路径中有非法字符)
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1027.html
Copyright © 2020-2023  润新知