新连连看
题目: http://acm.hrbeu.edu.cn/index.php?act=problem&id=1005&cid=18
Description 大家都玩过连连看吧!今天我们玩一个类似的游戏。在一个由10*10个小方格组成的矩形里有n(n<=10)对字符(它们是大写字符中的前n个)。矩形里有些位置是可以从上面走过,有些则不能。能走过的位置用'.'标识,不能的用'#'标识。如果2个相同字符是连通的(从一个字符能走到另一个字符,注意走的时候只能向上、下、左、右走。某个位置是有其他字符时,这个位置是不能走的),那么这对字符能够进行配对。如果将这对字符配对,这对字符将从这个矩形里消除,也就是说这2个字符所在的位置对于其他字符而言变成能走动了。 现在的问题是:请你决定这些字符的配对顺序(只有能配对才能进行配对),使得n对字符最后都配对成功。 Input 先给出一个正整数t(t<=10),表示有t组测试数据。 每组测试数据有10行组成,每行有10个字符。这些字符只能是'.','#',或者是大写字符中的前n个。每组测试数据中不超过10对字符。 Output 如果能够使每组测试数据中的n对字符配对成功,输出配对的顺序。如果有多种配对成功的顺序,输出字典序最小的那组。 否则输出"My God!"。 Sample Input 2 ABF....... CE........ D......... .......... .......... .......... .......... .........D ........EC .......FBA ABF....... CE........ D......... .......... .......... .........# ........#D .........# ........EC .......FBA Sample Output DCABEF My God!
解题思路:
用map存储每对字符的位置, map有自动排序的功能, 所以默认是以字典顺序遍历的. 在遍历map中的每个字符时, 检测当前字符是否可以连通至另一相同字符, 检查连通性可以用广度优先算法(深度优先重复太多).
#include <iostream> #include <map> #include <string> #include <queue> #include <iterator> using namespace std; const int N = 10; int n; char bon[N][N]; struct point{ int x; int y; } point1, point2; map<char, point> m; map<char, point>::iterator it; char c; bool visit[N][N]; int step[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; int basei ; int basej ; /************************************************************************/ /* 广度优先算法 需要使用队列 */ /************************************************************************/ bool bfs(point p, char base){ queue<point> points; //存储可走节点的队列 points.push(p); memset(visit,false,sizeof(visit)); //重要: 算法开始前将所有位置设置为未访问false; while(!points.empty()){ //队列不空时循环 point tmp = points.front(); points.pop(); int i = tmp.x; int j = tmp.y; for(int k=0;k<4;k++) //遍历周围4个方向的节点 { int ti=i+step[k][0]; int tj=j+step[k][1]; if(ti>=0 &&ti<N && tj>=0&&tj<N &&bon[ti][tj]==base && !visit[ti][tj]) { if (basei !=ti || basej!=tj) //不能等于他自己 { bon[ti][tj] = '.'; return true; } else { visit[ti][tj] = true; } } if(ti>=0 &&ti<N && tj>=0&&tj<N &&bon[ti][tj]=='.' && !visit[ti][tj]) //如果是可行节点'.' ,将其加入队列中. { visit[ti][tj] = true; point2.x = ti; point2.y = tj; points.push(point2); //将可走节点压入队列中 } } } return false; } int main(){ cin>>n; for (int i=0; i<n; i++) { for (int j=0; j<N; j++) { for (int k=0; k<N; k++) { point1.x = j; point1.y = k; cin>>c; if (c != '.' && c != '#') { m[c] = point1; } bon[j][k] = c; } } string ans = ""; if (m.empty()) //没有任何字符的情况 { cout<<"My God!"<<endl; return 1; } while(!m.empty()){ //map中还有字符就循环 int flag = 0; for (it = m.begin(); it != m.end(); ++it) { point tmp = it->second; char tmpc = it->first; basei = tmp.x; basej = tmp.y; if(bfs(tmp, tmpc)){ //当前字符能够消除 flag = 1; ans = ans + tmpc; bon[tmp.x][tmp.y] = '.'; m.erase(tmpc); break; } } if (flag == 0) //所有字符都不能消除. { ans = "My God!"; break; } } cout<<ans<<endl; m.clear(); //重要: 将上一组数据清除. } return 0; }