zoukankan      html  css  js  c++  java
  • P4049 [JSOI2007]合金

    传送门

    好巧妙的题啊...

    首先因为 $a+b+c=1$,所以我们忽略 $c$,只要确定出 $a,b$ 即可

    考虑构建平面直角坐标系,横坐标为 $a$,纵坐标为 $b$,那么一种原料或者合金 $v_1=(a_1,b_1)$ 就可以看成平面上的一个向量

    而如果某两种原料 $v_1,v_2$ 可以构成一种合金,那么有 $k_1v_1+k_2v_2=(k_1+k_2)v_3$,当然也可以写成 $k_1v_1+k_2v_2=v_3,k_1+k_2=1$

    根据初中的理论,$av_1+(1-a)v_2,a in [0,1]$ 这个向量的终点在 $v_1,v_2$ 两个终点的连线上

    所以两种原料能够组成的合金在它们终点的连线上

    考虑三个向量的情况,首先其中两个可以组合出一个线段,线段的任意一点都可以和第三个向量组合,所以三个向量能够组成他们凸包内的向量

    多个向量也是同样的道理,所以只要求出能包围所有合金点的原料点构成的凸包的最小点数

    枚举任意两个原料点,如果合金都在连边的左侧则它们的连边可以作为凸包的一部分,否则不能

    注意特判合金在边上的情况,只有当在线段上时此边才合法

    然后 $floyd$ 跑最小环即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    typedef double db;
    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<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=507,INF=1e9+7;
    const db eps=1e-9;
    inline bool fc(db x,db y) { return fabs(x-y)<eps; }
    struct Point {
        db x,y;
        Point (db a=0,db b=0) { x=a,y=b; }
        inline Point operator + (const Point &tmp) const {
            return Point(x+tmp.x,y+tmp.y);
        }
        inline Point operator - (const Point &tmp) const {
            return Point(x-tmp.x,y-tmp.y);
        }
        inline bool operator != (const Point &tmp) const {
            return fabs(x-tmp.x)>eps||fabs(y-tmp.y)>eps;
        }
        inline void print() { cout<<x<<" "<<y<<endl; }
    }C[N],D[N];
    inline db Cross(Point A,Point B) { return A.x*B.y-A.y*B.x; }
    inline db Dot(Point A,Point B) { return A.x*B.x+A.y*B.y; }
    int n,m,mp[N][N];
    inline bool check(Point S,Point T)
    {
        for(int i=1;i<=m;i++)
        {
            db t=Cross(T-S,D[i]-S);
            if(t<-eps) return 0;
            else if(fabs(t)<eps&&Dot(T-D[i],S-D[i])>eps) return 0;
        }
        return 1;
    }
    int main()
    {
        db a,b,c; n=read(),m=read();
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&a,&b,&c);
            C[i]=Point(a,b);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%lf%lf%lf",&a,&b,&c);
            D[i]=Point(a,b);
        }
        memset(mp,0x3f,sizeof(mp));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                    mp[i][j]=(check(C[i],C[j]) ? 1 : INF);
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++) mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
        int ans=mp[0][0];
        for(int i=1;i<=n;i++) ans=min(ans,mp[i][i]);
        if(ans>=INF) printf("-1
    ");
        else printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    解析XML
    事务
    js小工具
    plsql用过的流程语句
    查询语句
    存储过程
    用过的CRT命令
    mysql常用命令
    Spirng MVC demo 完整示例01 环境搭建
    jmeter多个http请求串联
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11427920.html
Copyright © 2011-2022 走看看