题目链接:
HDU 1175 连连看:http://acm.hdu.edu.cn/showproblem.php?pid=1175
HDU 1728 逃离迷宫:http://acm.hdu.edu.cn/showproblem.php?pid=1728
简述 :
两个题可以放在一起进行练习,虽然他们的题目不同,但是思路一样(换汤不换药)。他们的相似之处就是转弯问题,连连看转弯次数为2次,逃离迷宫转弯次数可变。直接DFS肯定会超时,因此我们需要剪枝。
剪枝:
在这里我们要用到一个二维数组turn[maxn][maxn]来进行记录转弯的次数。
在这里有两个重要剪枝:
当不需要转弯时: if(turn[tx][ty] < turn[x][y]) continue;
当在转弯处的时: if(turn[tx][ty] < turn[x][y] + 1) continue;
聪明的你是否还有疑问?
当然你会问:为什么没有 turn[tx][ty] == turn[x][y] 呢?
代码实现:
HDU 1175 连连看:
注释:co为了记录方向。
#include <iostream>
#include <cstring>
#define Max 9999999
using namespace std;
int m,n;// m行 ,n列
const int maxn = 1e3+10;
int map[maxn][maxn]; // 存图
int vis[maxn][maxn];
int turn[maxn][maxn]; // 转向
int mark,dx,dy,ex,ey,k = 2;
int xx[4] = {0,0,-1,1};
int yy[4] = {1,-1,0,0};
void DFS(int x,int y,int co) {
if(x == ex && y == ey && turn[x][y] <= k) {
mark = 1;
return;
}
if(mark) return;
if(turn[x][y] > k) return;
if( x != ex && y !=ey && turn[x][y] == k) return ;
for(int i = 0; i < 4; i++) {
int tx = x + xx[i];
int ty = y + yy[i];
if(turn[tx][ty] < turn[x][y]) continue;
if(co != -1 && co != i && turn[tx][ty] < turn[x][y] + 1) continue;
if(tx <= 0 || ty <= 0 || tx > n || ty > m || map[tx][ty] || vis[tx][ty]) continue;
if(co != -1 && co != i) turn[tx][ty] = turn[x][y] + 1; //转弯
else turn[tx][ty] = turn[x][y];
vis[tx][ty] = 1;
DFS(tx,ty,i);
vis[tx][ty] = 0;
}
}
int main() {
while(~scanf("%d%d",&n,&m) && n && m) {
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++)
scanf("%d",&map[i][j]);
}
int q;
scanf("%d",&q);
while(q--){
memset(turn,Max,sizeof(turn));
scanf("%d%d%d%d",&dx,&dy,&ex,&ey);
if(map[dx][dy] != map[ex][ey] || !map[dx][dy] || !map[ex][ey]) {
printf("NO\n");
continue;
}
turn[dx][dy] = 0;
int temp = map[ex][ey];
map[ex][ey] = 0;
mark = 0;
DFS(dx,dy,-1);
if(mark) printf("YES\n");
else printf("NO\n");
map[ex][ey] = temp;
}
}
return 0;
}
HDU 1728 逃离迷宫 :
#include <iostream>
#include <cstring>
#define Max 99999999
using namespace std;
const int maxn = 510;
char map[maxn][maxn]; // 存图
int turn[maxn][maxn];// 转方向
int k,dx,dy,ex,ey,n,m;
int xx[4]={1,-1,0,0};
int yy[4]={0,0,1,-1};
int mark;
void DFS(int x,int y,int co) {
//剪枝
if(x == ex && y == ey && turn[x][y] <= k) {
mark = 1;
return;
}
if(turn[x][y] > k) return;
if(x != ex && y != ey && turn[x][y] == k) return ;
for(int i = 0; i < 4; i++) {
int tx = x + xx[i];
int ty = y + yy[i];
if(tx<=0 || ty<=0 || tx>n || ty>m || map[tx][ty]=='*') continue;
if(turn[tx][ty] < turn[x][y]) continue;
if(co != -1 && i != co && turn[tx][ty] < turn[x][y] + 1) continue;
map[tx][ty] = '*';
if(co != -1 && i != co) turn[tx][ty] = turn[x][y] + 1 ; // 方向转变
else turn[tx][ty] = turn[x][y]; // 方向不变
DFS(tx,ty,i);
map[tx][ty] = '.';
if(mark) return;
}
}
int main() {
int t;
scanf("%d\n",&t);
while(t--) {
memset(turn,Max,sizeof(turn));
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++)
scanf(" %c",&map[i][j]);
}
mark = 0;
scanf("%d%d%d%d%d",&k,&dy,&dx,&ey,&ex);
turn[dx][dy] = 0;
DFS(dx,dy,-1);
if(mark) printf("yes\n");
else printf("no\n");
}
return 0;
}
/*
5
6 7
..*..*.
*...*..
.**.***
..*.**.
*...***
..*.***
10 1 1 1 6
6 7
..*..*.
*...*..
.**.***
..****.
*...***
..*.***
10 1 1 1 6
6 7
..*..*.
*...*..
.**.***
..*.**.
*...***
..*.***
6 1 1 1 6
6 7
..*..*.
*...*..
.**.***
..*.**.
*...***
..*.***
8 1 1 1 6
6 7
..*..*.
*...*..
.**.***
..*.**.
*...***
..*.***
5 1 1 1 6
yes
no
yes
yes
no
*/
完美撒花!