您的位置:首页 > Web前端 > AngularJS

ACM UVa算法题209 Triangular Vertices的解法

2008-04-10 00:19 489 查看
有一段时间没有做ACM算法题目了,今天正好有空便随便挑了209题来做做:ACM UVa算法题#209题这道题有几个要点:1.   给定坐标系坐标系很容易定,我采用的是第一个点为(0, 0)点,X方向差别为2个单位,Y方向差别为1个单位,点之间的距离,也就是LEN为1个单位,这样便于计算。注意我用的不是实际长度,而是抽象的单位,这个单位在不同方向上面意义不一样,否则很容易通过三角形相关公理推出这样的三角形不存在,我们关心的只是这样的一个对应关系。这里的人为设定确实有些Confusing,我之前也是按照一般的三角形的长度,如3,4,5来定义,但是后来发现这样做做的乘除法太多,过于浪费CPU Cycle,如果按照我这样的设定,大部分情况只用到加减法,另外一种情况只需用到移位操作即可。参看下图:

2.   判断是否两点连线是一条边(Coincide)这里可以分两种情况:a.   Y1 = y2, 必然是Coincideb.   否则,X_Delta = abs(x1 – x2), Y_Delta = abs(y1 – y2), 由于之前我们人为设定X方向差别为2个单位,Y方向差别为1一个单位,因此只要X_Delta = Y_Delta即可 3.   计算距离假定是Coincide的情况,否则直接返回出错,因为在非Coincide的情况无需计算距离。此外,由于这里已经知道是Coincide,并且我们并没有统一单位,所以这里不能也不应该用勾股定理来计算长度,而是采用比例的方法,同样分两种情况,参考上图:a.   Y1 = y2, 那么因为X方向上两个单位对应一个长度Unit,所以长度=abs(x1 – x2) >> 1;b.   否则,长度Unit的个数和X/Y方向(任意)的差别相等,也就是长度=abs(x1 – x2) 4.   判断是否是目标图形,并且每条边相等对于三角形,很简单,直接对3条边判断即可,没有什么变数。对于四边形和六边形就不同了,需要用到遍历来确定一个从某点开始(我们可以固定为第一个点)遍历所有点最后回到该点的环,并且每条边长度均相等,注意这里由于题目的特殊性,不用判断平行等条件。可以用一个邻接矩阵来代表对应的边的长度,这个应该一次性计算出来,如果非Coincide则设置为某个特殊值,比如0刚开始提交的时候,Rank是45,之后我又做了下面的优化:1.   当遍历尝试完毕从最初点出发的某条边的时候,说明这一边不可能成为环,将其置为0表示不可通,并且遍历从最初点出发的其他同样长度的边,置为0,减少遍历次数2.   在初始化计算所有点的坐标的时候改变了一点点算法,用加减法代替乘法3.   最初坐标采用的是实际的长度,而不是像上面那样用不同的抽象单位算出,修改之后减少了大量乘除法计算4.   调整遍历算法,由于从初始点出发之后,后3个点必然不能是初始点,因此做了一点修改对这个情况作了优化5.   修改对邻接矩阵的算法,由于adj[i][j] = adj[j][i],所以只需计算矩阵的一半即可修改之后再提交Rank变成了33,似乎是目前个人的最好纪录 J
32 0.170 792  LittleJohn Yo C 2002-02-04 07:02:47 732386
33 0.172 1160  Yi Zhang C++ 2007-05-02 16:05:54 5551868
34 0.174 404  Rodrigo Malta Schmidt C 2001-08-30 08:46:54 539862
 代码如下:

// 


// ACM UVa Problem #209


// http://acm.uva.es/p/v2/209.html


//


// Author:  ATField


// Email:   atfield_zhang@hotmail.com


//




#include 


#include 


#include 




#define MAX    65535




struct point




...{


public :


    bool is_coincide(const point &pt) const




    ...{


        // not allow testing points with same coordinates


        if( _x == pt._x && _y == pt._y )


            return false;




        if( _y == pt._y )


            return true;


        else




        ...{


            int k1 = abs( _x - pt._x );


            int k2 = abs( _y - pt._y );




            if( k1 == k2 )


                return true;


        }




        return false;


    }




    int get_dist(const point &pt) const




    ...{


        // not allow testing points with same coordinates


        if( _x == pt._x && _y == pt._y )


            return 0;




        if( _y == pt._y )


            return abs(_x - pt._x) >> 1;        // need to divide by 2


        else




        ...{


            int k1 = abs( _x - pt._x );


            int k2 = abs( _y - pt._y );




            if( k1 == k2 )


                return k1;


        }




        return 0;


    }




public :


    static const int X_DELTA = 2;


    static const int Y_DELTA = 3;


    static const int LEN = 4;




public :


    int        _x;


    int        _y;


    int     _valid;




private :


    static point s_all_points[MAX];




public :


    static void prepare()




    ...{


        int level = 0;


        int before_next_level = 1;


        int next_x = 0;


        int next_y = 0;




        for( int i = 1; i < MAX ; ++i )




        ...{


            s_all_points[i]._x = next_x;


            s_all_points[i]._y = next_y;


            before_next_level--;




            if( before_next_level == 0 )




            ...{


                level++;


                before_next_level = level + 1;


                next_x = -level;


                next_y++;


            }


            else


                next_x += 2;




        }






    }




    static point *all_points()




    ...{


        return s_all_points;


    }


};




point point::s_all_points[MAX];




bool check_triangle(int *n)




...{


    // 1. Duplicates


    // No need to check duplicate because the following checks will do




    // 2. Coincide


    // Check every edge


    point *points = point::all_points();


    if( points[n[0]].is_coincide(points[n[1]]) &&


        points[n[0]].is_coincide(points[n[2]]) &&


        points[n[1]].is_coincide(points[n[2]]) )




    ...{


        // 3. Same length


        // Check every edge


        int len = points[n[0]].get_dist(points[n[1]]);


        if( len == points[n[0]].get_dist(points[n[2]]) &&


            len == points[n[1]].get_dist(points[n[2]]) )


            return true;


    }




    return false;


}






bool init_adj(int *n, int num, int adj[6][6])




...{


    point *points = point::all_points();




    for( int i = 0; i < num; ++i )




    ...{


        for( int j = i; j < num; ++j )




        ...{


            if( i == j )




            ...{


                adj[i][j] = 0;


                adj[j][i] = 0;


            }


            else




            ...{


                // 1. Duplicates


                // Return false when found duplicate


                if( n[i] == n[j] )


                    return false;




                // 2. Coincide & Len (When not coincide, len = 0)


                adj[i][j] = points[n[i]].get_dist(points[n[j]]);


                adj[j][i] = adj[i][j];


            }


        }


    }


        




    return true;


}




int find_same_len_loop(int adj[6][6], int num)




...{


    int stack[6];


    int used[6];


    int next[6];




    for( int i = 1; i < num; ++i )




    ...{         


        int len = adj[0][i];




        // skip non-connected dots


        if( len == 0 ) continue;




        // initialize "used" array & "next" array


        for( int j = 0; j < num; ++j )




        ...{


            used[j] = 0;


        }        


        


        int top = 0;


        stack[0] = i;


        used[i] = 1;


        next[0] = -1;




        top++;




        while( top > 0 )




        ...{


            next[top-1]++;




            // checked all the connected points?


            if( next[top-1] >= num )




            ...{


                // yes, then pop the stack


                top--;


                used[stack[top]] = 0;


            }


            else




            ...{


                int next_point = next[top-1];




                // follow non-used, same-length edge


                if( used[next_point] == 0 && len == adj[stack[top-1]][next_point] )




                ...{


                    stack[top] = next_point;


                    used[next_point] = 1;




                    // don't allow pushing 0 into stack before the last point


                    if( top < num - 1 ) 


                        next[top] = 0;


                    else


                        next[top] = -1;




                    top++;




                    // stack is full? found a loop


                    if( top == num )


                        return len;


                }


            }


        }




        // if this doesn't work, delete all edges starting from id 0 of this len


        for( int j = i; j < num; ++j )


            if( adj[0][j] == len )


                adj[0][j] = 0;


    }




    return 0;


}




bool check_parallelogram(int *n)




...{


    int adj[6][6];


    if(!init_adj(n, 4, adj))


        return false;           // found duplicate




    if(find_same_len_loop(adj, 4))


        return true;




    return false;


}




bool check_hexagon(int *n)




...{


    int adj[6][6];


    if(!init_adj(n, 6, adj))


        return false;           // found duplicate




    if(find_same_len_loop(adj, 6))


        return true;




    return false;


}




int main(int argc, char *argv[])




...{


    point::prepare();


    


    while(1)




    ...{


        char input[255];


        if( gets(input) == NULL )


            break;


        else if( strlen(input) == 0 )


            break;


        


        int n[6];


        int fields = sscanf( input, "%d %d %d %d %d %d", &n[0], &n[1], &n[2], &n[3], &n[4], &n[5] );




        printf("%s ", input);                    




        switch(fields)




        ...{


            case 3:




                ...{


                    bool is_triangle = check_triangle(n);




                    if( is_triangle )




                    ...{


                        puts("are the vertices of a triangle");


                        continue;


                    }




                    break;


                }




            case 4:




                ...{


                    bool is_parallelogram = check_parallelogram(n);




                    if( is_parallelogram )




                    ...{


                        puts("are the vertices of a parallelogram");


                        continue;


                    }




                    break;


                }




            case 6:




                ...{


                    bool is_hexagon = check_hexagon(n);




                    if( is_hexagon )




                    ...{


                        puts("are the vertices of a hexagon");


                        continue;


                    }




                    break;


                }


        }




        puts("are not the vertices of an acceptable figure");




    }




    return 0;


}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: