PK ACM 1021

来源:互联网 发布:淘宝拍a发b那个平台好 编辑:程序博客网 时间:2024/06/01 08:37

下午闲来没事,做了到北大ACM的题目,题目不难,就是有些工作量,当然我的也没有进行进一步的优化,通过就好。下面是原题:

Description

The 2D-Nim board game is played on a grid, with pieces on the grid points. On each move, a player may remove any positive number of contiguous pieces in any row or column. The player who removes the last piece wins. For example, consider the left grid in the following figure.

The player on move may remove (A), (B), (A, B), (A, B, C), or (B,F), etc., but may not remove (A, C), (D, E), (H, I) or (B, G).
For purposes of writing 2D-Nim-playing software, a certain programmer wants to be able to tell whether or not a certain position has ever been analyzed previously. Because of the rules of 2D-Nim, it should be clear that the two boards above are essentially equivalent. That is, if there is a winning strategy for the left board, the same one must apply to the right board. The fact that the contiguous groups of pieces appear in different places and orientations is clearly irrelevant. All that matters is that the same clusters of pieces (a cluster being a set of contiguous pieces that can be reached from each other by a sequence of one-square vertical or horizontal moves) appear in each. For example, the cluster of pieces (A, B, C, F, G) appears on both boards, but it has been reflected (swapping left and right), rotated, and moved. Your task is to determine whether two given board states are equivalent in this sense or not.

Input

The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by the input data for each test case. The first line of each test case consists of three integers W, H, and n (1 ≤ W, H ≤ 100). W is the width, and H is the height of the grid in terms of the number of grid points. n is the number of pieces on each board. The second line of each test case contains a sequence of n pairs of integers xi , yi, giving the coordinates of the pieces on the first board (0 ≤ xi < W and 0 ≤ yi < H). The third line of the test case describes the coordinates of the pieces on the second board in the same format.

Output

Your program should produce a single line for each test case containing a word YES or NO indicating whether the two boards are equivalent or not.

Sample Input

2

8 5 11

0 0 1 0 2 0 5 0 7 0 1 1 2 1 5 1 3 3 5 2 4 4

0 4 0 3 0 2 1 1 1 4 1 3 3 3 5 2 6 2 7 2 7 4

8 5 11

0 0 1 0 2 0 5 0 7 0 1 1 2 1 5 1 3 3 6 1 4 4

0 4 0 3 0 2 1 1 1 4 1 3 3 3 5 2 6 2 7 2 7 4

Sample Output

YES

NO
 
题目意思很明确,很容易想到思路就是首先识别出map里面得cluster,然后比较各个cluster是否相同即可。这里可以把map用位图来储存或者直接存放到一个矩阵里面。题目讲图形最大为100*100, 实际上也花不了多少空间,存成矩阵最大的好处是判断相邻比较方便,并且不需要为cluster保留其包含的点;位图则可以节省很多的空间。我已开始使用的是位图的表示,某位为1则表示被占用,当插入一个点时,判断其邻居是否已有点被占用。找到第一个被占用的邻居,将此点并入该cluster;如果还有点属于别的cluster,则合并两个cluster。另外一种方法是首先将全部图形都存放到位图里面,然后用穷举的方法检测各个点的连通性。这个方法的效率应该比第一种方法要好一些,因为可以避免每次都对每个cluster的node来检测是否相邻。
用意思的可能是比较cluster是否一致。我开始想的是用各个边缘点到形心的连线形成的夹角来判断,但是有几个问题。首先要检测边缘点,这个可以通过检查该点的邻居(必须是8个邻居点)是否都在cluster中来判断;另外就是求夹角的话,要对连线进行“排序”,这是一个麻烦事。努力地几次以后放弃这个方法。
后来想到其实不用这么麻烦,直觉上,如果cluster的个数一致,那么如果个点到形心的距离一样的话,那么也cluster也应该是一样的。这种方法应该适用很多的例子,但是要求严格的话,应该还是要对各个点的顺序有一定的要求。
下面是我的代码。第一次编译错误,报告说找不到memset,所以改用循环清空map的位图。第二次答案错误,经过应用别的同学的测试用例,修改了几处错误,终于通过。
代码占用的内存有700k,也比较长。高手都在几十k的条件下就可以搞定,很是厉害。不知用的什么方法,又得同学讲用图的联通子数,我还没有仔细想过如何实现。

#include
#include
#include
#include
#include

using namespace std;

struct node{
        int x;
        int y;
};

struct cluster{
        vector nodes;
        float cx,cy; /*the coordinate of the shape center*/
        list distances;
};

struct map{
        int h,w;
        int pieces;
        unsigned char bits[(100*100)/8];
        list clusters;
}gMaps[2];

//#define __DEBUG
#ifdef __DEBUG
#define DEBUG(str) cout<<
#else
#define DEBUG(str)
#endif

/*
**@ return the node'a value: 0--no piece, not 0(possibly not 1)--having piece
**  w is the width of the map
**  i is the ROW and j is the COLUMN
*/
#define GETNODE(i,j,map) (map.bits[(i*map.w+j)/8]& (char(1)<<((i*map.w+j)%8)))
#define SETNODE(i,j,map) (map.bits[(i*map.w+j)/8]|=(char(1)<<((i*map.w+j)%8)))

void insert_node(struct map &map, int x, int y)
{
        bool update=false;
        //DEBUG("insert node("<<<","<<<")");
        /*BE CAUTION: x is the column and y is row*/
        /*at first, we find if (x,y) has neighbours*/
        if((x>0 && GETNODE(y, (x-1), map)!=0)
           || (x<(map.w-1) && GETNODE(y, (x+1), map)!=0)
           || ((y>0) && GETNODE((y-1), x, map)!=0)
           || (y<(map.h-1) && GETNODE((y+1), x, map)!=0))
        {
                update=true;
        }
        SETNODE(y, x, map);

        if(update==false)
        {
                /*create a new cluster*/
                DEBUG("A new cluster");
                struct cluster clu;
                struct node n = {x,y};
                clu.nodes.push_back(n);
                map.clusters.push_back(clu);
                return;
        }

        /*update map's clusters*/
        list &clusters = map.clusters;
        list::iterator iter=clusters.begin();
        bool first=true;
        list::iterator updatedCluster = clusters.begin();/*the first value*/
        while(iter!=clusters.end())
        {
                list::iterator curIter = iter++;
                /*is (x,y) surroundded by this cluster?*/
                vector::iterator nodeIter=curIter->nodes.begin();
                while(nodeIter!=curIter->nodes.end())
                {
                        if( (nodeIter->x==x && nodeIter->y==(y-1))
                                ||(nodeIter->x==x && nodeIter->y==(y+1))
                                ||(nodeIter->x==(x-1) && nodeIter->y==y)
                                ||(nodeIter->x==(x+1) && nodeIter->y==y))
                        {
                                if(first==true)
                                {
                                        struct node n={x,y};
                                        curIter->nodes.push_back(n);
                                        updatedCluster = curIter;
                                        first=false;
                                }
                                else
                                {/*merge this cluster into the previous one*/
                                        //cout<<"merging"<
                                        updatedCluster->nodes.insert(updatedCluster->nodes.end(), curIter->nodes.begin(), curIter->nodes.end());
                                        clusters.erase(curIter);
                                }
                                break;
                        }
                        nodeIter++;
                }
        }

}

bool comp_cluster(struct cluster &a, struct cluster &b)
{
        if(a.nodes.size()!=b.nodes.size())
        {
                return a.nodes.size()>b.nodes.size()?true:false;
        }

        /*if the size if the same, then compare the distances*/
        list::iterator disIterA=a.distances.begin();
        list::iterator disIterB=b.distances.begin();
        for(;disIterA!=a.distances.end() && disIterB!=b.distances.end(); disIterA++, disIterB++)
        {
                if(*disIterA>*disIterB)
                {
                        return true;
                }
                else if(*disIterA<*disIterB)
                {
                        return false;
                }
        }
        return true;/*if the same, then return true*/

}

void calculate_dis(struct cluster &cluster)
{
        /*get the center of the shape*/
        if(cluster.nodes.size()==1)
        {
                return;
        }
        float x=0,y=0;
        vector::iterator iter=cluster.nodes.begin();
        for(;iter!=cluster.nodes.end();iter++)
        {
                x+=float(iter->x);
                y+=float(iter->y);
        }
        x = x/float(cluster.nodes.size());
        y = y/float(cluster.nodes.size());

        iter=cluster.nodes.begin();
        for(;iter!=cluster.nodes.end();iter++)
        {
                float dis=(float(iter->x)-x)*(float(iter->x)-x)+(float(iter->y)-y)*(float(iter->y)-y);
                cluster.distances.push_back(dis);
        }
        cluster.distances.sort();
#ifdef __DEBUG
        list::iterator i=cluster.distances.begin();
        cout<<"The sorted distances:/n";
    for(;i!=cluster.distances.end();i++)
    {
                cout<<*i<<"    ";
        }
        cout<
#endif
}

bool is_the_same(struct map &mapA, struct map &mapB)
{
        if(mapA.clusters.size()!=mapB.clusters.size())
        {
                return false;
        }

        list::iterator clusterIterA = mapA.clusters.begin();
        list::iterator clusterIterB = mapB.clusters.begin();

        for(;clusterIterA!=mapA.clusters.end(); clusterIterA++)
        {
                calculate_dis(*clusterIterA);
        }
        //cout<<"Another"<
    for(;clusterIterB!=mapB.clusters.end(); clusterIterB++)
    {
        calculate_dis(*clusterIterB);
    }

        /*we sort the clusters according the cluster's node size desc*/
        mapA.clusters.sort(comp_cluster);
        mapB.clusters.sort(comp_cluster);

        for(clusterIterA=mapA.clusters.begin(), clusterIterB=mapB.clusters.begin(); clusterIterA!=mapA.clusters.end() && clusterIterB!=mapB.clusters.end(); clusterIterA++, clusterIterB++)
        {
                if(clusterIterA->distances.size()!=clusterIterB->distances.size())
                {
                        return false;
                }
                list::iterator angleIterA = clusterIterA->distances.begin();
                list::iterator angleIterB = clusterIterB->distances.begin();

                for(; angleIterA!=clusterIterA->distances.end() && angleIterB!=clusterIterB->distances.end() ; angleIterA++, angleIterB++)
                {
                        //cout<<*angleIterA<<","<<*angleIterB<
                        if(fabs(*angleIterA-*angleIterB)>0.0001)
                        {
                                return false;
                        }
                }
        }

        return true;
}

void clear_map(struct map &map)
{
        int i;
        for(i=0;(i*8)
        {
                map.bits[i]=0;
        }
        map.w=0;
        map.h=0;
        map.pieces=0;

        map.clusters.clear();
}

int main()
{
        int mapNumber;
        vector res;
        /*first, we get the map*/
        cin>>mapNumber;
        while(mapNumber-->0)
        {
                clear_map(gMaps[0]);
        clear_map(gMaps[1]);

                int i=0;
                cin>>gMaps[0].w>>gMaps[0].h>>gMaps[0].pieces;
                gMaps[1].w=gMaps[0].w, gMaps[1].h=gMaps[0].h, gMaps[1].pieces=gMaps[0].pieces;
                while(i<2)
                {
                        int idx=0;
                        while(idx++
                        {
                                int x,y;
                                cin>>x>>y;
                                insert_node(gMaps[i], x, y);
                        }
                        i++;
                }
                bool same=is_the_same(gMaps[0], gMaps[1]);
                res.push_back((same!=true?"NO":"YES"));
        }

        vector::iterator iter=res.begin();
        for(;iter!=res.end();iter++)
        {
                cout<<*iter<
        }

        return 0;
}

原创粉丝点击