Hoj 11195

Hoj 11195
题目链接: http://acm.hnu.cn:8080/online/?action=problem&type=show&id=11195

#include  < iostream >
#include 
< string .h >
#include 
< math.h >
#define  eps 1e-3

using   namespace  std;

struct  point
{
    
double  x, y;
    point(){}
    
void  read(){
        scanf(
" %lf,%lf " & x,  & y);
    }
    
void  write(){
        printf(
" %.0lf,%.0lf\n " , x, y);
    }
};
struct  line
{
    
char  flag;
    point a, b;
    line(){}
    
void  read(){
        getchar();
        scanf(
" %c %lf,%lf %lf,%lf " & flag,  & a.x,  & a.y,  & b.x,  & b.y);
    }
    
void  write(){
        printf(
" %c %.0lf,%.0lf %.0lf,%.0lf\n " , flag, a.x, a.y, b.x, b.y);
    }
};
// 精度控制 
int  sig( double  a)
{
return  (a  >  eps)  -  (a  <   - eps);}

// 判两直线平行
int  parallel(point u1,point u2,point v1,point v2){
    
return  sig((u1.x - u2.x) * (v1.y - v2.y) - (v1.x - v2.x) * (u1.y - u2.y));
}

// 计算cross product (P1-P0)x(P2-P0)
double  xmult(point p1,point p2,point p0){
    
return  (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
//  (op-sp)·(op-ep)点积 
double  dotmul(point sp, point ep, point op){
    
return  (op.x - sp.x)  *  (op.x - ep.x)  +  (op.y - sp.y)  *  (op.y - ep.y); 
}


// 判两点在线段异侧,点在线段上返回0
int  opposite_side(point p1,point p2,point l1,point l2){
    
return  xmult(l1,p1,l2) * xmult(l1,p2,l2) <- eps;
}

// 判两线段相交,不包括端点和部分重合
int  intersect_ex(point u1,point u2,point v1,point v2){
    
// if(!parallel(u1,u2,v1,v2))
         return  opposite_side(u1,u2,v1,v2) && opposite_side(v1,v2,u1,u2);
    
// else return 0;
}

// 计算两直线交点,注意事先判断直线是否平行!
point intersection(point u1,point u2,point v1,point v2){
    point ret
= u1;
    
double  t = ((u1.x - v1.x) * (v1.y - v2.y) - (u1.y - v1.y) * (v1.x - v2.x))
            
/ ((u1.x - u2.x) * (v1.y - v2.y) - (u1.y - u2.y) * (v1.x - v2.x));
    ret.x
+= (u2.x - u1.x) * t;
    ret.y
+= (u2.y - u1.y) * t;
    
return  ret;
}

// 一个double的平方
double  sqr( double  a)
{
return  a * a;} 

// 返回p向量的模的平方
double  mo(point p)
{
return  p.x * p.x  +  p.y * p.y;} 

// 两点距离 
double  dist(point a, point b)
{
return  sqrt( sqr(a.x  -  b.x)  +  sqr(a.y  -  b.y) );}

//  返回点p以点o为圆心逆时针旋转alpha(单位:弧度)后所在的位置
point rotate(point o,  double  alpha, point p)
{
    point tp;
    p.x 
-=  o.x; p.y  -=  o.y;
    tp.x
= p.x * cos(alpha)  -  p.y * sin(alpha) + o.x;
    tp.y
= p.y * cos(alpha)  +  p.x * sin(alpha) + o.y;
    
return  tp;
}

//  返回顶角在o点,起始边为os,终止边为oe的夹角(单位:弧度)
double  angle(point o, point s, point e)
{
    point os, oe;
    os.x 
=  s.x  -  o.x; os.y  =  s.y  -  o.y;
    oe.x 
=  e.x  -  o.x; oe.y  =  e.y  -  o.y;
    
double  cosfi, norm, fi; 
    cosfi 
=  dotmul(s, e, o);
    norm 
=  sqrt(mo(os)  *  mo(oe));
    cosfi 
/=  norm;
    
if (sig(cosfi  -   1.0 >=   0  )  return   0 ;
    
if (sig(cosfi  +   1.0 <=   0  )  return  M_PI;
    fi 
=  acos(cosfi);
    
// o.write(); s.write(); e.write();
     return  fi;
}

// 返回op向量与线段s反射的向量(p在s上) 
point reflct(point o, point p, line s)
{
    point new_dic;
    
double  ang  =  angle(p, o, s.a);
    
if ( sig(ang  -  M_PI / 2 >   0 ) ang  =  M_PI  -  ang;
    ang 
=  M_PI  -   2   *  ang;
    new_dic 
=  rotate(p, ang, o);
    
if (angle(p, o, s.a)  !=  angle(p, new_dic, s.b) ) new_dic  =  rotate(p,  2 * M_PI - ang, o);
    new_dic.x 
-=  p.x;
    new_dic.y 
-=  p.y;
    
return  new_dic;
}

line l[
101 ];
int  n, answer[ 101 ];

struct  nod
{
    point ini, dic;
}q[
101 ];

void  work(point a, point b)
{
    
int  cnt  =   0 , close  =   - 1 , open  =   0 ;
    point exp, new_ini, ini 
=  a, dic  =  b, cro, new_dic;
    
double  mindis;
    
int  minnum;
    memset(answer, 
0 sizeof (answer));
    q[
0 ].ini  =  ini;
    q[
0 ].dic  =  dic;    
    
while (close  <  open)
    {
        close 
++ ;
        ini 
=  q[close].ini;
        dic 
=  q[close].dic;
        exp.x 
=  ini.x  +   5000   *  dic.x;
        exp.y 
=  ini.y  +   5000   *  dic.y;
        
// 把射线变成线段 
         int  i;
        mindis 
=   999999999.0 ;    minnum  =   - 1 ;

        
for (i  =   0 ; i  <  n; i  ++ )
        {
            
if ( intersect_ex(ini, exp, l[i].a, l[i].b) ) // 两线段相交 
            {  
                new_ini 
=  intersection(ini, exp, l[i].a, l[i].b);

                
if ( mindis  >  dist( ini, new_ini) )
                {
                    minnum 
=  i;
                    mindis 
=  dist(ini, new_ini);
                }
            }
        }
        new_ini 
=  intersection(ini, exp, l[minnum].a, l[minnum].b);
        
if (minnum  ==   - 1 continue ;
        
if (l[minnum].flag  ==   ' D '
        {
            answer[minnum] 
=   1 ;
            
continue ;
        }
        
if (l[minnum].flag  ==   ' S ' )
        {
            open 
++ ;
            q[open].ini 
=  new_ini;
            q[open].dic 
=  dic;
        }
        open 
++ ;
        new_dic 
=  reflct(ini, new_ini, l[minnum]);
        q[open].ini 
=  new_ini;
        q[open].dic 
=  new_dic;
    }
}

void   out ()
{
    
int  flag  =   0 ;
    
for ( int  i  =   0 ; i  <  n; i  ++ if (answer[i]) 
    {
        flag 
=   1 ;
        printf(
" %d\n " ,i  +   1 );
    }
    
if ( ! flag) puts( " NO BEAMS DETECTED " );
}

int  main()
{
    
int  test, x  =   0 ;
    point ini, dic;
    scanf(
" %d " & test);
    
while (test  --  )
    {
        printf(
" DATA SET #%d\n " , ++ x);
        ini.read();    dic.read();
        scanf(
" %d " & n);
        
for ( int  i  =   0 ; i  <  n; i  ++
        {
            l[i].read();
        }
        work(ini, dic);
        
out ();
    }
}


你可能感兴趣的:(Hoj 11195)