题目描述
大家都玩过连连看吧!今天我们玩一个类似的游戏。在一个由10*10个小方格组成的矩形里有n(n<=10)对字符(它们是大写字符中的前n个)。矩形里有些位置是可以从上面走过,有些则不能。能走过的位置用’.’标识,不能的用’#’标识。如果2个相同字符是连通的(从一个字符能走到另一个字符,注意走的时候只能向上、下、左、右走。某个位置是有其他字符时,这个位置是不能走的),那么这对字符能够进行配对。如果将这对字符配对,这对字符将从这个矩形里消除,也就是说这2个字符所在的位置对于其他字符而言变成能走动了。

现在的问题是:请你决定这些字符的配对顺序(只有能配对才能进行配对),使得n对字符最后都配对成功。

输入
先给出一个正整数t(t<=10),表示有t组测试数据。
每组测试数据有10行组成,每行有10个字符。这些字符只能是’.’,’#’,或者是大写字符中的前n个。每组测试数据中不超过10对字符。

输出
如果能够使每组测试数据中的n对字符配对成功,输出配对的顺序。如果有多种配对成功的顺序,输出字典序最小的那组。
否则输出”My God!”。

样例输入
2
ABF…….
CE……..
D………
……….
……….
……….
……….
………D
……..EC
…….FBA
ABF…….
CE……..
D………
……….
……….
………#
……..#D
………#
……..EC
…….FBA
样例输出
DCABEF
My God!
思路:先按照字典序找出所有的字母,然后用BFS依次判断能否成对消除。 在这个题中,最容易想到的是用一个for循环查找字母字符,但是循环次数太多,担心超限(勉强卡过去)。 无论是一次找出所有的字母,还是找到一个就调用BFS判断能否消除,这两种思路的队列必须要用数组模拟!(可能有别的思路,也可能可以调用库函数,太渣,目前不会。。) 下面的做法用到了map,这个STL是默认为按字典序排序的(从小到大) 所以可以节约时间,但调用了库函数,会增加时间,这个时间相比循环查找单个字母字符的少得多,故最终用时比它少。 当然,觉得不保险的话,可以自己排下顺序

#include<cstdio>
#include<map>
#include<iostream>
#include<queue>
#include<iterator>
#include<cstring>
#include<string> ///string类型头文件
using namespace std;
const int N=10;
int dxy[4][2]= {1,0,0,1,-1,0,0,-1};
char a[N][N];///输入的字符数组
int visit[N][N];///标志数组
struct point //记录字符的坐标(x,y)
{
    int x,y;
} kk,po,que[505];
int bx,by;
bool in(int x,int y) //判断坐标(x,y)是否合法
{
    if(x>=0&&x<N&&y>=0&&y<N)
        return true;
    return false;
}
map<char,point>mp;  
map<char,point>::iterator it; ///迭代器
bool bfs(point pp,char ch)///判断能否成对消除字母
{
    memset(visit,false,sizeof(visit)); ///标志置零
    int flag=0,front=1,rear=1; //front为队头,rear为队尾
    que[front].x=bx;
    que[front].y=by;
    visit[bx][by]=1;
    while(front<=rear&&!flag) ///当队列不为空并且flag为0(flag=1时,即可以消除该字母)
    {
        int i=que[front].x;
        int j=que[front].y;
        for(int k=0; k<4; k++)
        {
            int nx=i+dxy[k][0];
            int ny=j+dxy[k][1];
            if(in(nx,ny)&&(a[nx][ny]=='.'||a[nx][ny]==ch)&&!visit[nx][ny]) //字符是"."时,加入队尾,是ch时,就消除
            {
                visit[nx][ny]=1;
                rear++;
                que[rear].x=nx;
                que[rear].y=ny;
                if(a[nx][ny]==ch)
                {
                    a[nx][ny]=a[bx][by]='.'; ///这里被坑了很久,把bx,by写成了i,j;过了样例,却WA了。。   没有自己造的数据给自己挖了一个坑
                    flag=1;
                    break;
                }
            }
        }
        front++;//删除队头
    }
    return flag?true:false;
}

int main()
{
    int n;
    //freopen("E:/in.txt","r",stdin);
    scanf("%d",&n);
    while(n--)
    {
        for(int i=0; i<N; i++)
        {
            scanf("%s",a[i]);
            for(int j=0; j<N; j++)
            {
                po.x=i,po.y=j;
                if(a[i][j]!='.'&&a[i][j]!='#')
                    mp[a[i][j]]=po;///mp[a[i][j]]是子母时对应的坐标(i,j)的结构体po
            }
        }
        string ans="";///输出的字母序列
        if(mp.empty())///若没有字母,就直接输出
        {
            printf("My God!\n");
            continue;
        }
        while(!mp.empty())//有字母时
        {
            int flag=0;
            for(it=mp.begin(); it!=mp.end(); it++)
            {
                point tp=it->second;
                char tpch=it->first;
                bx=tp.x,by=tp.y;
                if(bfs(tp,tpch))///如果字母tpch能够消除
                {
                    flag=1;
                    ans=ans+tpch;///加在ans后面
                    mp.erase(tpch);
                    break;
                }
            }
            if(!flag)///如果不能全部消除
            {
                ans="My God!";
                break;
            }
        }
        char p[25];
        strcpy(p,ans.c_str());//转换为char * 类型,以便用printf输出,若不这样处理,会时间超限
        printf("%s\n",p);
        mp.clear();///mp清空便于下次的处理
    }
    return 0;
}

这里用到了STL中的map, 这是一种容器,默认按键的字典序排序的,在这段代码中,键就是char,值就是point(结构体类型)
char *p;
strcpy(p,ans.c_str());
printf(“%s\n”,p);
这里是将string类型的ans转化为char* 类型用printf输出,比cout输出(流)用时少