回 帖 发 新 帖 刷新版面

主题:第69次编程比赛题目

题目:平面上有一堆随机分布的点,都有x,y坐标。任意给定一个点A,在这些点中快速找出三个点,它们构成的三角形正好包围点A(点A可以在三角形的边上,但三角形的三个点不能在同一直线上)。要求找出的三个点离点A的距离和最小。

// x[] -- 所有点的x坐标
// y[] -- 所有点的y坐标
// n   -- 点数(3<=n<=1000000)
// x0,y0 -- 点A的坐标
// 【返回值】三个点到点A的最小距离和,如果无解则返回0
double MinDistance(int x[], int y[], int n, int x0, int y0, char *id)
{
    strcpy(id, "");    // 请在""中填入你的id,主要是方便输出测试结果
        // ...
}

判断标准:
(1)正确
(2)时间效率
(3)空间效率
(4)可读性

比赛时间:
    2008年7月17日12:00 -- 2008年7月24日12:00

回复列表 (共21个回复)

沙发

沙发。。。

板凳

水平低,只能用笨办法实现了,等高手的,学习ing

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctime>
#include <iostream>

using namespace std;
/********************
存储点的坐标
********************/
struct POINT
{
       int x;
       int y;
      // POINT(int a=0; int b=0){ x=a; y=b;}//constructor
};

/****************************************************************************** 
r=CrossProduct(sp,ep,op),得到(sp-op)和(ep-op)的叉积 
r>0:ep在矢量opsp的逆时针方向; 
r=0:opspep三点共线; 
r<0:ep在矢量opsp的顺时针方向 
*******************************************************************************/ 
double CrossProduct(POINT sp,POINT ep,POINT op) 

    return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y)); 

        
/**********************************
判断点p1,p2是否在ab所确定的直线的同侧
***************************************/
int SameSide(POINT p1,POINT p2,POINT a,POINT b)
{
    double cp1,cp2;
    cp1 = CrossProduct(b,p1,a);
    cp2 = CrossProduct(b,p2,a);
    if ( cp1*cp2 > 0 || cp1 ==0)
    { 
      //printf("两点在同侧"); 
      return 1;
    }
    else 
      return 0;
}

/*******************************
判断点p是否在abc组成的三角形内
*******************************/
int PointInTriangle(POINT p,POINT a,POINT b,POINT c)
{
    if (SameSide(p,a, b,c) && SameSide(p,b,a,c) && SameSide(p,c,a,b)) 
    {
        return 1;
    }
    else 
    {
        return 0;
    }
}

double MinDistance(int x[], int y[], int n, int x0, int y0, char *id)
{
       strcpy(id, "liyaha");    // 请在""中填入你的id,主要是方便输出测试结果
       int i,j,k,tag=1;
       POINT a,b,c,p;
       int flag; //flag:存储点是否在三角形内信息,1为在,0不在 
       double res,min;
       p.x = x0;
       p.y = y0;
       for (i = 0; i < n; i++)
       {
           a.x = x[i]; a.y= y[i];
           for(j=i+1; j< n; j++)
           {
               b.x = x[j]; b.y= y[j];
               for(k=j+1; k<n; k++)
               {
               c.x = x[k]; c.y= y[k];
               if(p.x>a.x && p.x> b.x && p.x>c.x)
                   continue;
               if(p.x<a.x && p.x< b.x && p.x<c.x)
                   continue;
               if(p.y>a.y && p.y> b.y && p.y>c.y)
                   continue;
               if(p.y<a.y && p.y< b.y && p.y<c.y)
                   continue;
               flag = PointInTriangle(p,a,b,c);
               if(flag)
               {
                   res = sqrt((x0-a.x)*(x0-a.x)+(y0-a.y)*(y0-a.y))
                       + sqrt((x0-b.x)*(x0-b.x)+(y0-b.y)*(y0-b.y)) 
                       + sqrt((x0-c.x)*(x0-c.x)+(y0-c.y)*(y0-c.y)) ; 
                                      if(tag ==1){ min = res; tag =0;}
                   if(res < min)
                        min= res;
               } //if
               } //for k
           } //for j
       }//for i
       return min>0?min:0;
}

3 楼

有什么奖励呢

4 楼


////////////////////////////////////////////
//MinDistance需要使用以下三个函数
////////////////////////////////////////////

//按距离排序
void sort_point(int* x,int* y,double *dist,int start,int end);
//判断是否在三角形内
char in_triangle(int xa,int ya,int xb,int yb,int xc,int yc,int x0,int y0);
//移动指针
char get_next(int& pa,int& pb,int& pc);

double MinDistance(int x[], int y[], int n, int x0, int y0, char *id)
{
    strcpy(id, "scutdx2005");

    double* dist=(double *)malloc(n*sizeof(double));
    //计算距离的平方
    for(int i=0;i<n;i++)
    {
        dist[i]=(x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0);
    }
    //排序各个点
    sort_point(x,y,dist,0,n-1);
    
    int pa=0,pb=1,pc=2;
    double min_value=-1,now_value;
    //搜索
    while(pc<n)
    {
        now_value=-1;
        //如果当前三角形满足条件
        if(in_triangle(x[pa],y[pa],x[pb],y[pb],x[pc],y[pc],x0,y0)==1)
        {
            now_value=sqrt(dist[pa])+sqrt(dist[pb])+sqrt(dist[pc]);
            //记录最小值
            if((min_value==-1||now_value<min_value))
            {
                min_value=now_value;
            }
        }
        //返回最小值
        if(get_next(pa,pb,pc)==1&&min_value!=-1)
        {
            return min_value;
        }
    }
    return 0;
}

void sort_point(int* x,int* y,double *dist,int start,int end)
{
//使用快速排序法
    if(start>=end)
        return;
    int lp=start,rp=end+1;
    double d=dist[start],dt;
    int x0=x[start],y0=y[start],it;
    
    while(true)
    {
        do
        {
            lp++;
        }while(dist[lp]<d);
        do
        {
            rp--;
        }while(dist[rp]>d);
        if(lp>=rp)
            break;
        //swap
        dt=dist[lp];dist[lp]=dist[rp];dist[rp]=dt;
        it=x[lp];x[lp]=x[rp];x[rp]=it;
        it=y[lp];y[lp]=y[rp];y[rp]=it;
    }
    dist[start]=dist[rp];
    x[start]=x[rp];
    y[start]=y[rp];
    dist[rp]=d;
    x[rp]=x0;
    y[rp]=y0;
    
    sort_point(x,y,dist,start,rp-1);
    sort_point(x,y,dist,rp+1,end);
}

char in_triangle(int xa,int ya,int xb,int yb,int xc,int yc,int x0,int y0)
{
    int A[3],B[3],C[3],t1,t2,t3;
    //计算三条直线的方程
    A[0]=yb-ya;
    B[0]=xa-xb;
    C[0]=-A[0]*xa-B[0]*ya;
    A[1]=yc-ya;
    B[1]=xa-xc;
    C[1]=-A[1]*xa-B[1]*ya;
    A[2]=yc-yb;
    B[2]=xb-xc;
    C[2]=-A[2]*xc-B[2]*yc;
    //如果三点在一条直线上,返回0
    if(A[0]*xc+B[0]*yc+C[0]==0)
    {
        return 0;
    }
    
    t1=(A[0]*x0+B[0]*y0+C[0])*(A[0]*xc+B[0]*yc+C[0]);
    t2=(A[1]*x0+B[1]*y0+C[1])*(A[1]*xb+B[1]*yb+C[1]);
    t3=(A[2]*x0+B[2]*y0+C[2])*(A[2]*xa+B[2]*ya+C[2]);
    if(t1>=0&&t2>=0&&t3>=0)
        return 1;
    else 
        return 0;
}

char get_next(int& pa,int& pb,int& pc)
{
    if((++pb)>=pc)
    {
        ++pa;
        pb=pa+1;
        if(pb>=pc)
        {
            ++pc;
            pa=0;
            pb=1;
            return 1;
        }
    }
    return 0;
}

5 楼

需要分割提交,无奈
//说明:一个三角形,如果A在其内部,那它与最长边的两点的斜率都应该小于或等于三角形第三点与这两点连线的斜率
#include "iostream"
#include "math.h"
#define N 7000
using namespace std;
double Slope(double a0,double b0,double a1,double b1)         //求斜率
{
    return (b0-b1)/(a0-a1);
}
double Distance(double x0,double y0,double x1,double y1,double x2,double y2,double x3,double y3)  //点A与三角形三点的距离和
{
    double dis;
    dis=sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1))+ 
        sqrt((x0-x2)*(x0-x2)+(y0-y2)*(y0-y2))+ sqrt((x0-x3)*(x0-x3)+(y0-y3)*(y0-y3));
    return dis;
}
double MinDistance(int x[],int y[],int n,int x0,int y0,char *id)
{
    strcpy(id, "apart789");    // 请在""中填入你的id,主要是方便输出测试结果
    int x1,y1,x2,y2,x3,y3;
    int i,k=0;
    double d1,d2,d3;           //为计算选点做准备
    double temp,dis=0;       
    for(i=0;i<n;i=i+3)
    {
        x1=x[i];
        y1=y[i];
        x2=x[i+1];
        y2=y[i+1];
        x3=x[i+2];
        y3=y[i+2];
        if((x1<x0&&x2<x0&&x3<x0)||(x1>x0&&x2>x0&&x3>x0)||(y1<y0&&y2<y0&&y3<y0)||(y1>y0&&y2>y0&&y3>y0))
            continue;
        if((x1==x2&&x2==x3)||(y1==y2&&y2==y3))
            continue;
        d1=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
        d2=(x1-x3)*(x1-x3)+(y1-y3)*(y1-y3);
        d3=(x2-x3)*(x2-x3)+(y2-y3)*(y2-y3);
        

6 楼

if(d1>d2&&d1>d3)                //取最长边的两点,最长边有三种情况,
  {
    if(x1<=x2)
     {
       if((Slope(x0,y0,x1,y1)<=Slope(x3,y3,x1,y1))&&(Slope(x0,y0,x2,y2)<=Slope(x3,y3,x2,y2)))
         {
           temp=Distance(x0,y0,x1,y1,x2,y2,x3,y3);
           if(k==0)                //第一次,先保存距离,以后就比较大小,存最小的距离
             {
                dis=temp;
                 k++;
              }
            else if(temp<dis)
                  dis=temp;
          }
     }
    else
     {
       if((Slope(x0,y0,x2,y2)<=Slope(x3,y3,x2,y2))&&(Slope(x0,y0,x1,y1)<=Slope(x3,y3,x1,y1)))
         {
           temp=Distance(x0,y0,x1,y1,x2,y2,x3,y3);
           if(k==0)
            {
              dis=temp;
              k++;
            }
            else if(temp<dis)
                   dis=temp;
         }
     }
  }
else if(d2>d1&&d2>d3)
      {
        if(x1<=x3)
         {
           if((Slope(x0,y0,x1,y1)<=Slope(x2,y2,x1,y1))&&(Slope(x0,y0,x3,y3)<=Slope(x2,y2,x3,y3)))
              {
                 temp=Distance(x0,y0,x1,y1,x2,y2,x3,y3);
                 if(k==0)
                   {
                     dis=temp;
                      k++;
                    }
                  else if(temp<dis)
                        dis=temp;
                }
          }
         else
           {
             if((Slope(x0,y0,x3,y3)<=Slope(x2,y2,x3,y3))&&(Slope(x0,y0,x1,y1)<=Slope(x2,y2,x1,y1)))
               {
                  temp=Distance(x0,y0,x1,y1,x2,y2,x3,y3);
                  if(k==0)
                    {
                        dis=temp;
                        k++;
                    }
                   else if(temp<dis)
                        dis=temp;
                }
            }
        }
        

7 楼

else if(d3>d1&&d3>d2)
        {
          if(x2<=x3)
           {
             if((Slope(x0,y0,x2,y2)<=Slope(x1,y1,x2,y2))&&(Slope(x0,y0,x3,y3)<=Slope(x1,y1,x3,y3)))
               {
                  temp=Distance(x0,y0,x1,y1,x2,y2,x3,y3);
                   if(k==0)
                    {
                        dis=temp;
                        k++;
                    }
                    else if(temp<dis)
                        dis=temp;
                  }
            }
         else
           {
             if((Slope(x0,y0,x3,y3)<=Slope(x1,y1,x3,y3))&&(Slope(x0,y0,x2,y2)<=Slope(x1,y1,x2,y2)))
                {
                   temp=Distance(x0,y0,x1,y1,x2,y2,x3,y3);
                    if(k==0)
                    {
                        dis=temp;
                        k++;
                    }
                    else if(temp<dis)
                        dis=temp;
                 }
            }
        }
 }
    return dis;
}
int main()
{
    int x[N],y[N];
    int i,x0,y0;
    char id[10]="";
    double dis;
    for(i=0;i<N;i++)
    {
        x[i]=rand();
        y[i]=rand();
    }
    cout<<"please input A:";
    cin>>x0;
    cin>>y0;
    dis=MinDistance(x,y,N,x0,y0,id);
    if(dis==0.0)
        cout<<"无解";
    else cout<<"the smallest distance is:"<<dis<<endl;
    getchar();
    return 0;
}

8 楼

不错。。。

9 楼

#include<stdio.h>
#include<math.h>
#include<malloc.h>
#include<string.h>
typedef struct sqlen{
    double len;
    int q;
} sqlen;
//测试函数,用来检验三个点是否满足条件    
int test(int x0,int y0,int x1,int y1,int x2,int y2,int x3,int y3)
    {
        int midx,midy;
        int k1,k2;
        int t1,t2;
        midx=(x1+x2)/2;
        midy=(y1+y2)/2;
        if((y1-y2)*(x1-x3)==(y1-y3)*(x1-x2)) return 0;//三点共线,不成立
        if((y1-y0)*(x2-x0)==(y2-y0)*(x1-x0)) return 1;//其中两点与已知点共线,一定满足条件
        k1=(midy-y0)*(x1-x0)-(y1-y0)*(midx-x0);
        k2=(midy-y0)*(x2-x0)-(y2-y0)*(midx-x0);
        t1=(y3-y0)*(x1-x0)-(y1-y0)*(x3-x0);
        t2=(y3-y0)*(x2-x0)-(y2-y0)*(x3-x0);
        if(k1*t1<0&&k2*t2<0) return 1 ;
        else return 0;
    }
double MinDistance(int x[], int y[], int n, int x0, int y0, char *id)
{
    double *Len;
    sqlen *sq;
    sq=(sqlen*)malloc(n*sizeof(sqlen));//记录距离及排序
    //计算各点到A的距离,并初始化排序数组sq
    int i,j,k;
    for(i=0;i<n;++i)
    {
        sq[i].len=(x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0);
        sq[i].q=i;
    }
    //用冒泡法对距离排序,并将序列存入sq
    sqlen sk;
    i=n-1;
    while(i>0)
    {
        int lastswap=0;
        for(j=0;j<i;++j)
            if(sq[j+1].len<sq[j].len)
            {
                sk=sq[j];
                sq[j]=sq[j+1];
                sq[j+1]=sk;
                lastswap=j;
            }
        i=lastswap;
    }
    //求出满足条件距离最小的三点和距离和
    int result[3],w=n;
    double sum=0.0,g;
    for(i=0;i<n;++i)
        for(j=i+1;j<n;++j)
            for(k=j+1;k<w;++k)
                {
                    if(test(x0,y0,x[sq[i].q],y[sq[i].q],x[sq[j].q],y[sq[j].q],x[sq[k].q],y[sq[k].q]))
                        {
                            result[0]=sq[i].q;
                            result[1]=sq[j].q;
                            result[2]=sq[k].q;
                            g=sqrt(sq[i].len)+sqrt(sq[j].len)+sqrt(sq[k].len);
                            if(sum==0.0||g<sum)
                                sum=g;
                            w=k;
                        }
                }
    printf("\n====================================================\n");
    printf("\n     所求点的坐标为:(%d,%d),(%d,%d),(%d,%d)",x[result[0]],y[result[0]],x[result[1]],y[result[1]],x[result[2]],y[result[2]]);
    return sum;
    strcpy(id, "ayxg");    // 请在""中填入你的id,主要是方便输出测试结果
 }
void main(void)
{
    char*p=0;
    int x[10]={1,2,3,4,9,5,1,6,3,1};
    int y[10]={0,1,2,3,4,5,6,7,8,9};
    int n=10,x0=4,y0=5;
    printf("\n      距离和为:%f\n",MinDistance(x,y,n,x0,y0,p));
    printf("\n=======================================================\n");
}

10 楼


辛苦了

我来回复

您尚未登录,请登录后再回复。点此登录或注册