C2

  题意就是给你n个点,保证无重点,然后问你n个点两两相连构成直线,这些直线会有多少个交点?

思路就是两条直线如果不是平行就是相交的,所有我们可以把全部直线都找出来,存到set里,然后对于一条直线在用map记录和它平行的直线的数量,那么对于这条直线产生的交点数量就是总的直线数-和它平行的直线数量了。

要唯一表示一条直线需要记录它的斜率和截距(直线方程为y=x*(y1-y2)/(x1-x2)-x1*(y1-y2)/(x1-x2)+y1,因为k=dy/dx,除法会有误差所以就没用k表示斜率,这里把等式变成(x1-x2)*y=x*(y1-y2)-x1*(y1-y2)+y1*(x1-x2),这里设y和x的系数为aa,bb,常数项为cc。然后就可以利用aa和bb表示斜率了,如果2条直线斜率相等的话,那么aa和bb的比例是相同的,因此每个直线对应的aa,bb都要化到互质,然后因为是个等式,所有这个cc也是要连带着化的,然后因为会有-y=-x,和y=x这种情况,所以要定个准,保证aa>=0。

#include<bits/stdc++.h>
using namespace std;
#define fuck(x) cout<<#x<<"    "<<x<<endl;
const int inf=0x3f3f3f3f;
#define ll long long
typedef pair<int,int> pii;
map<pii,int>mp;
set<pair<pii,int> >st;
pii nod[1005];
int gcd(int x,int y)
{
    return y==0?x:gcd(y,x%y);
}
int main()
{
    int n;
    ll ans=0,tmp=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&(nod[i].first),&(nod[i].second));
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            int dx=nod[i].first-nod[j].first,dy=nod[i].second-nod[j].second,aa,bb,cc,igcd;
            if(dx==0)
                aa=0,bb=1,cc=nod[i].first;
            else
               aa=dx,bb=dy,cc=-dy*nod[i].first+nod[i].second*dx;
            igcd=gcd(aa,bb);igcd=gcd(igcd,cc);
            aa/=igcd;bb/=igcd;cc/=igcd;
            if(aa<0) aa=-aa,bb=-bb,cc=-cc;
            if(!st.count(make_pair(make_pair(aa,bb),cc)))
                    st.insert(make_pair(make_pair(aa,bb),cc)),mp[make_pair(aa,bb)]++,tmp++;
        }
    set<pair<pii,int> >:: iterator it;
    for(it=st.begin();it!=st.end();it++)
        ans+=tmp-1LL*mp[(*it).first];
    printf("%lld
",ans/2);
    return 0;
}
原文地址:https://www.cnblogs.com/eason9906/p/11754767.html