ACM UVa算法题209 Triangular Vertices的解法

    技术2022-05-11  15

    有一段时间没有做ACM算法题目了,今天正好有空便随便挑了209题来做做:ACM UVa算法题#209

    这道题有几个要点:

    1.   给定坐标系

    坐标系很容易定,我采用的是第一个点为(0, 0)点,X方向差别为2个单位,Y方向差别为1个单位,点之间的距离,也就是LEN1个单位,这样便于计算。注意我用的不是实际长度,而是抽象的单位,这个单位在不同方向上面意义不一样,否则很容易通过三角形相关公理推出这样的三角形不存在,我们关心的只是这样的一个对应关系。这里的人为设定确实有些Confusing,我之前也是按照一般的三角形的长度,如345来定义,但是后来发现这样做做的乘除法太多,过于浪费CPU Cycle,如果按照我这样的设定,大部分情况只用到加减法,另外一种情况只需用到移位操作即可。

    参看下图:

    2.   判断是否两点连线是一条边(Coincide)

    这里可以分两种情况:

    a.   Y1 = y2, 必然是Coincide

    b.   否则,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

    刚开始提交的时候,Rank45,之后我又做了下面的优化:

    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  < stdio.h > #include  < stdlib.h > #include  < string .h > #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;        forint 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();    forint i = 0; i < num; ++i )    {        forint 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];    forint i = 1; i < num; ++i )    {                 int len = adj[0][i];        // skip non-connected dots        if( len == 0 ) continue;        // initialize "used" array & "next" array        forint 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        forint 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;}

    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1595174


    最新回复(0)