搜索算法 problem(1009)

来源:互联网 发布:网络侵犯著作权案例 编辑:程序博客网 时间:2024/06/06 15:36

1.简明题意

就是我们平时玩的连连看的游戏规则,刚开始用的广搜,刚开始的剪枝不高效导致爆掉队列,使得内存超限,后来发现,bfs先遍历的点不一定是弯数少的点,这样的话如果不专门来更新的话,就会出现运行结果跟搜索顺序有关,是左上右下还是左下右上等等序列

2.解题思路

因为至多两个弯,而数据量是1000*1000的,用dfs搜索的时候,只要找到合法解就行,不需要找弯数最少等最优情况,所以只要找到合法解就进行全局标记,这样其他就不需要搜索了,综合的效率其实非常高,大约在o(kn)级别,而且k不很大,具体也不好推算。后来又加了一个剪枝,即当弯数为二时,若此时点的方向不能直接到达目标点就减去此点,很好理解,因为不满足的话到目标点就必须要拐弯,所以弯数就会超过2,但此剪枝的效率并不高,节省大约20mm

3.AC代码

#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <queue>#include <climits>using namespace std;const int MAX = 1003;const int dirx[5] = {0,0,1,0,-1};const int diry[5] = {0,1,0,-1,0};bool visit[MAX][MAX];int map[MAX][MAX];int wan[MAX][MAX];int n,m,bx,by;bool mark;bool yes(int x,int y,int dir){int dx = bx - x;int dy = by - y;if(dx!=0)dx = dx/abs(dx);if(dy!=0)dy = dy/abs(dy);if(dx==dirx[dir] && dy==diry[dir])return true;else return false;}void dfs(int x,int y,int cnt,int dir){int i,tx,ty;if(mark)return;if(x<1 || y<1 || x>n || y>m || cnt>2)return;//注意下面几个剪枝的顺序,顺序搞错了就会出错,因为最后一个元素非0if(x==bx && y==by){mark = true;return;}if(cnt==2 && !yes(x,y,dir))return;//这个剪枝不强力,加了此剪枝时间只减少了18msif(map[x][y]!=0)return;if(wan[x][y]!=-1 && wan[x][y]<=cnt)return;wan[x][y] = cnt;for(i=1;i<=4;++i){tx = x + dirx[i];ty = y + diry[i];if(dir!=i){dfs(tx,ty,cnt+1,i);}else{dfs(tx,ty,cnt,i);}}}int main(){//freopen("in.txt","r",stdin);int i,j,t,ax,ay;while(scanf("%d %d",&n,&m)!=EOF){if(n==0 && m==0)break;for(i=1;i<=n;++i){for(j=1;j<=m;++j){scanf("%d",&map[i][j]);}}scanf("%d",&t);while(t--){memset(wan,-1,sizeof(wan));scanf("%d %d %d %d",&ax,&ay,&bx,&by);mark = false;if(map[ax][ay]!=map[bx][by] || map[ax][ay]==0){printf("NO\n");continue;}wan[ax][ay] = 0;for(i=1;i<=4;++i){dfs(ax+dirx[i],ay+diry[i],0,i);}if(mark){printf("YES\n");}else{printf("NO\n");}}}    return 0;}



0 0
原创粉丝点击