bzoj 1027: [JSOI2007]合金

好多特判。。。(我只写了一个)

凸包+Floyd    还学到了怎么判断点线位置

/*
    万万没想到是个几何题 
    首先 z是没用的 因为x,y确定了 那么z就确定了
    x,y看做笛卡尔坐标
    要是一个东西能被两个东西合成 那么一定在两个东西的连线上
    如果是被多个东西合成  那么就是在这几个东西构成的凸包内(圈) 
    直接n^3判断所有点在不在这条边的同一侧 
    注意是同一侧 因为要围成 圈 (凸包)嘛 
    之后就是Floyd跑最小环 
    注意 在线段上 和在所在直线上和并且在线段外 这两种情况 
    还要注意点就在线段端点位置。。。 
    S(P1,P2,P3)=|y1 y2 y3|= (x1-x3)*(y2-y3)-(y1-y3)*(x2-x3) 
    如果S(A,B,C)为正数,则C在矢量AB的左侧; 
    如果S(A,B,C)为负数,则C在矢量AB的右侧; 
    如果S(A,B,C)为0,则C在直线AB上。
    这个公式其实就是俩斜率公式 的变形。。。 
    注意特判全部点都在一起的时候。。。 QwQ函数 
*/
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define db double
const db eps=1e-9; 
using namespace std;
const int N=550;
int n,m,dis[N][N];
db x[N],y[N],_x[N],_y[N];
void Init()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lf%lf%*lf",&x[i],&y[i]);
    for(int i=1;i<=m;i++) scanf("%lf%lf%*lf",&_x[i],&_y[i]);
}
int Work(int i,int j,int k)
{
    double res=(x[i]-_x[k])*(y[j]-_y[k])-(y[i]-_y[k])*(x[j]-_x[k]);
    if(fabs(res)<=eps)
    {
        if(_x[k]<x[i]&&_x[k]<x[j]) return 2;
        if(_x[k]>x[i]&&_x[k]>x[j]) return 2;
        if(_y[k]<y[i]&&_y[k]<y[j]) return 2;
        if(_y[k]>y[i]&&_y[k]>y[j]) return 2;
        return 4;
    }
    return (res>=0); 
}
void Solve()
{
    memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++) if(i!=j) 
    {
        int p=0,p0=0,p1=0;
        for(int k=1;k<=m;k++)
        {
            int t=Work(i,j,k);
            if(t==0||t==2) {p=1;break;} 
// 只能在同一侧 我们默认为返回 1 是符合条件的吧 都无所谓 
// 返回2 是指在所在直线上和并且在线段外 坑定不行 
        }
        if(!p) dis[i][j]=1;
    }
}
void Floyd()
{
    for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    int ans=dis[0][0];
    for(int i=1;i<=n;i++) ans=min(ans,dis[i][i]);
    if(ans==dis[0][0]) ans=-1;
    printf("%d\n",ans);
}
bool QwQ() 
{
    for(int i=1;i<=n;i++)
    {
        int p=1;
        for(int j=1;j<=m;j++)
            if(fabs(x[i]-_x[j])>eps||fabs(y[i]-_y[j])>eps) {p=0;break;}
        if(p) {puts("1");return 1;} 
    } return 0;
}
int main()
{
    Init();
    if(QwQ()) return 0;
    Solve();
    Floyd();
    return 0;
}

 

转载于:https://www.cnblogs.com/lxy8584099/p/10187786.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值