【STSRM13】木之本樱

本文介绍了一种计算平面上给定直线集合中所有交点数量的算法,并提供了两种实现方式:一种是O(n^3)的时间复杂度,通过枚举每一对直线找到交点并计算经过这些交点的其他直线的数量;另一种是更高效的O(n^2*logn)算法,通过先计算所有交点再进行排序和计数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题意】抽象模型后转化为:给定n个直线,ans+=C(x,4)*8,x为每个经过直线数>=4的点的直线数,不存在平行直线。

【算法】数学

【题解】

运用了一个很简单的道理:经过同一个点的线段互相相交。

O(n^3),枚举直线i和j相交,然后枚举后面直线判断是否过交点的条数x,将C(x,2)累加入答案。

O(n^2*log n),只要O(n^2)跑一边交点(不去重),排序,统计相同交点有几个就可以得知经过该交点的直线数了。

访问x次,则可由1+2+3+...+n-1=x求得n。

注意多关键字double排序。

注意eps=1e-6足矣。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
int read()
{
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c=='-')t=-1;
    do{s=s*10+c-'0';}while(isdigit(c=getchar()));
    return s*t;
}
/*------------------------------------------------------------*/
const int inf=0x3f3f3f3f,maxn=810,maxN=640100;
const double eps=1e-6;
struct cyc{double x,y;}anss[maxN];
int n,x1[maxn],x2[maxn],y1_[maxn],y2[maxn],tot;
double k[maxn],b[maxn];
ll c[maxn],d[maxN];
void insert(double x,double y){anss[++tot].x=x;anss[tot].y=y;}
bool cmp(cyc a,cyc b){return fabs(a.x-b.x)>eps?a.x<b.x:a.y<b.y;}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        x1[i]=read(),y1_[i]=read(),x2[i]=read(),y2[i]=read();
        if(x2[i]-x1[i])k[i]=1.0*(y2[i]-y1_[i])/(x2[i]-x1[i]);
        b[i]=1.0*y1_[i]-k[i]*x1[i];
    }
    tot=0;
    for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++){
            if(x2[i]-x1[i]==0){
                if(x2[j]-x1[j]==0)continue;
                insert(x1[i],k[j]*x1[i]+b[j]);
            }else if(x2[j]-x1[j]==0){
                insert(x1[j],k[i]*x1[j]+b[i]);
            }else{
                double X=(b[i]-b[j])/(k[j]-k[i]);
                double Y=k[i]*X+b[i];
                insert(X,Y);
            }
        }
    }
    sort(anss+1,anss+tot+1,cmp);
    c[4]=1;
    for(int i=5;i<=n;i++)c[i]=c[i-1]*i/(i-4);
    ll number=3;
    for(int i=4;i<=n;i++){number+=i-1;d[number]=i;}
    ll ans=0,num=0;
    anss[0].x=anss[0].y=-1;
    for(int i=1;i<=tot;i++)if(fabs(anss[i].x-anss[i-1].x)<eps&&fabs(anss[i].y-anss[i-1].y)<eps)num++;else{
        ans+=c[d[num]];num=1;
    }
    ans+=c[d[num]];
    printf("%lld",ans*8);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/onioncyc/p/7346770.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值