TOJ3112: 单词串串烧(回溯)
传送门(<--可以点击的)
时间限制(普通/Java):1000MS/3000MS 内存限制:65536KByte
描述
“单词串串烧”是一款拼词智力游戏,给定4*4的方格,随机取16个大写字母置于16个方格之中,玩家从任意一个方格出发,从一个字母沿相邻(上、下、左、右,左上、左下、右上、右下8个方向都算相邻)方格可以找到另一字母,将这些字母串联起来可以组成许多不同的单词。现在的问题是先给出一个单词,需要你开动脑筋写一个程序来判断是否能够从这些方格中的字母拼出给定的单词,但要注意:在同一个单词中任何一个方格只能使用1次。
比如:
P R G N
G O E I
R S M Y
A M E D
可以拼出“PROGRAMMING”、“SOME”、“RED”,但不能拼出“PROGRAMMER”,因为最后一个R重复使用了。
输入
输入数据有多组,每组数据的第1行为一个由大写字母组成的单词,不超过16个字母。接下来有4行,每行4个大写字母,组成4*4的方格。输入数据以EOF结束。
输出
对每组输入数据,判断是否可以拼出该单词,如果可以输出yes,否则输出no。
样例输入
PROGRAMMING
PRGN
GOEI
RSMY
AMED
ROSEMARY
AMED
RSMY
GOEI
PRGN
样例输出
yes
no
思路:简单回溯题,记录一下第一个字符出现的位置,然后深搜找就行。
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<string.h> #include<string> #include<cstdlib> #include<cmath> #include<stack> #include<queue> #include<set> #include<map> #include<vector> #define ll long long using namespace std; int go[8][2]={{-1,0},{1,0},{0,-1},{0,1},{1,1},{1,-1},{-1,1},{-1,-1}}; char ma[10][10]; bool check(int x,int y){ if(x < 0 || x >= 4 || y < 0 || y >= 4){ return false; } return true; }//判断是否越界 int vis[4][4],f; void dfs(int x,int y,string cmp,string now){ vis[x][y] = 1; if(now.size()+1 ==cmp.size()) f = 1; for(int i = 0 ; i < 8 ; i++){ int dx = x + go[i][0]; int dy = y + go[i][1]; if(!vis[dx][dy] && check(dx,dy) && ma[dx][dy] == cmp[now.size()+1]){ vis[dx][dy] = 1; dfs(dx,dy,cmp,now+ma[dx][dy]); vis[dx][dy] = 0;//回溯思想 } } } int main(){ string cmp; while(cin>>cmp){ int ex[100],ey[100],k = 0; //这里我用ex ey数组存出现第一个字符的横纵坐标,作为深搜的起点。 for(int i = 0 ; i < 4 ; i++){ scanf("%s",ma[i]); for(int j = 0; j < 4 ;j++){ if(ma[i][j] == cmp[0]){ ex[k] = i; ey[k++] = j; } }//记录出现第一个字符的横纵坐标 } f = 0;//记录是否已经找到 for(int i = 0 ; i < k ; i++){ memset(vis,0,sizeof(vis));//每次清空vis数组 dfs(ex[i],ey[i],cmp,"");//分别代表 进入深搜的横纵坐标,需要匹配的串,以及空串。 if(f)break; } f?puts("yes"):puts("no"); } }