三角形


【 问题描述 】
 平面上有N条直线,用方程A i x + B i y +C i
=0表示。这些直线没有三线共点的。现在
要你计算出用这些直线可以构造出多少三
角形?
【 输入格式 】
 第1行:一个整数N(1 ≤ N≤ 300000)。
 下面N行:每行3个整数:Ai, Bi 和Ci,
表示对应直线方程的系数。不超过10^9.

 

 



【 数据规模与约定 】
对于40%的数据,N ≤1000;

对于100%的数据,N≤300000。

 

 

 

 

题解:考试的时候想打个暴力,应该能得30分,但只得了15分,后来发现多判断了y2与y3是否相交,若只是这样,还不会出错,但是判断的时候误写成了A1*B2-B1*B2!=0,追悔莫及,画蛇添足,还添错了。先找出两两相交的直线,然后从1到n枚举每条直线y1,枚举与它相交的直线y2,再枚举与y2相交的直线y3,根据相交直线的公式A1*B2-B1*A2!=0来判断y3是否与y1相交,若满足,则说明三条直线能围成一个三角形.

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
#define N 5010
using namespace std;
int n;
ll ans=0;
int f[N][N],num[N]={0};
struct node
{
    int a,b,c;
}fc[N];
int main()
{
    freopen("trokuti.in","r",stdin);
    freopen("trokuti.out","w",stdout);
    
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
      scanf("%d%d%d",&fc[i].a,&fc[i].b,&fc[i].c);
    for (int i=1;i<=n-1;i++)
      for (int j=i+1;j<=n;j++)
         if ((fc[i].a*fc[j].b-fc[i].b*fc[j].a)!=0) f[i][++num[i]]=j; 
    for (int i=1;i<n;i++)
      for (int j=1;j<=num[i];j++)
        {
            int x=f[i][j];
            int y=num[x];
            for (int k=1;k<=y;k++)
              {
                   int kk=f[x][k];
                   if ((fc[i].a*fc[kk].b-fc[i].b*fc[kk].a)!=0) ans++; 
              }
             
        }
    cout<<ans<<endl;
      
    fclose(stdin);
    fclose(stdout);
    
    return 0;                                                      
}
30

 

正解:由于任意三条互不平行且非三线共点的直线均能围成一个切仅一个三角形。而题目中说不存在三线共点的情况,所以只需统计出所有直线组合中三线都互不平行的数量即可。判断是否相交时,可用斜率进行判断,统计斜率不同的直线y的数量,并统计出与y平行的直线的数量(即与y斜率相同的直线)。

 然后用计算出n条直线中取出3条直线有多少种不同的方案数。然后减去平行直线的组合方案数(包含三条直线中有两条直线平行,三条直线均互相平行)。即为最终答案。

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<map>
#define M 300000
#define ll long long
const int N=-1e9;
using namespace std;
int n,num=0;
ll ans;
double a[M];
map<double,int>f;//用map映射,妈妈再也不用担心会爆炸啦。 
ll c(int x,int y)//从x中取出y个数的不同的方案数 
{
    ll kk=1;
    if (x<y) return 0;
    for (int i=x;i>=x-y+1;i--) kk*=i;
    for (int i=1;i<=y;i++) kk/=i;
    return kk; 
}
int main()
{
    freopen("trokuti.in","r",stdin);
    freopen("trokuti.out","w",stdout);
    scanf("%d",&n);
    for (int i=1,A,B,C;i<=n;i++)
      {
           scanf("%d%d%d",&A,&B,&C);
           if (B==0)
             f[N]++;//由于斜率可能不存在,因此用负无穷来储存这一情况 
           else
             {
                double k=(double(A)/B)*1.0;
              if (!f[k]) a[++num]=k;
              f[k]++;     
           }
      }
    if (f[N]) a[++num]=N;
    ans=c(n,3); 
    for (int i=1;i<=num;i++)
      {
           int k=f[a[i]];
           ans-=c(k,3);//三条直线均互相平行的可能 
           ans-=c(k,2)*(n-k);//三条直线中两条直线互相平行的可能 
      }
    cout<<ans<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}
100

 

posted @ 2016-10-25 20:31  外婆桥  阅读(229)  评论(0编辑  收藏  举报