【JSOI2007】bzoj1027 合金

229 篇文章 0 订阅
177 篇文章 0 订阅

可以发现比重只用考虑两维,因此可以把原料看成平面上的点,若干个原料能合成的区域就是凸包。
这样问题变成了求一个点集 A 的最小子集,使得围成的凸包包含另一个点集B的所有点。可以枚举 A 中的边,如果b中的所有点都在它左侧就连一条有向边。最后floyd找最小环就是答案。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-10;
const int maxn=510,oo=0x3f3f3f3f;
int cmp(double x)
{
    if (x>eps) return 1;
    if (fabs(x)<=eps) return 0;
    return -1;
}
struct Vector
{
    double x,y;
    void rd()
    {
        scanf("%lf%lf%*lf",&x,&y);
    }
    Vector operator + (const Vector &v) const
    {
        return (Vector){x+v.x,y+v.y};
    }
    Vector operator - (const Vector &v) const
    {
        return (Vector){x-v.x,y-v.y};
    }
}a[maxn],b[maxn];
typedef Vector Point;
double dot(Vector v,Vector u)
{
    return v.x*u.x+v.y*u.y;
}
double cross(Vector v,Vector u)
{
    return v.x*u.y-v.y*u.x;
}
struct Segment
{
    Point a,b;
};
int m,n,dis[maxn][maxn];
int check(Segment s)
{
    int x;
    for (int i=1;i<=n;i++)
    {
        x=cmp(cross(s.b-s.a,b[i]-s.a));
        if (x==1||(x==0&&
            cmp(dot(b[i]-s.a,b[i]-s.b))==1))
                return 0;
    }
    return 1;
}
int main()
{
    int ans=oo;
    scanf("%d%d",&m,&n);
    for (int i=1;i<=m;i++) a[i].rd();
    for (int i=1;i<=n;i++) b[i].rd();
    for (int i=1;i<=m;i++)
        for (int j=1;j<=m;j++)
            dis[i][j]=check((Segment){a[i],a[j]})?1:oo;
    for (int k=1;k<=m;k++)
        for (int i=1;i<=m;i++)
            for (int j=1;j<=m;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    for (int i=1;i<=m;i++) ans=min(ans,dis[i][i]);
    printf("%d\n",ans==oo?-1:ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值