最短路分类里的,zoj只有50个人过,暴汗,不过应该大多数是被冗长的题目给吓住了吧。
给你地图,图中的1代表这里有根据地,你越靠近根据地,越容易被敌人发现,危险等级越高。不能从根据地中间穿过。
给你起点,终点,求最少的危险等级和使之可以到达,如果没有 输出,no solution。
危险等级是这么定义的,你在某个点,这个点离它最近的根据地的距离为d,那么,这个点的危险等级就是,矩阵的长+宽-d。
我第一反应,这种图,不符合常规啊,就换了下,把图换成各自的点图,而不是用01代表格子。
这么做的好处很多哈,就是可以直观地算起点和终点了。弊端是在最后调试过程中发现的,下面会讲。
第一个BFS的工作是,把每个格子的危险等级算出来,采用用1的格子去BFS周围的格子。
第二个BFS就是利用优先队列去算从起点到达终点的最短路了。其中dd数组标记当前从s点到各个点的路,然后如果可以更新的话,就加入队列。我过了之后,把dd给去掉了,MLE了,队列存不下了 = =。。。其中判断不能从根据地里面过我写了个函数,经画图可以看到,只要11的同一侧有0,或者11 在边界处,肯定可以过去。
说下这么存的弊端了,样例过之后WA掉了。自己做了几个数据,发现问题了。看下图右边。
图中也解释了。右边粉色圆圈画起来的,这种情况,都被1 1 覆盖掉了,但是其实中间那俩11还是可以通过的。这时候就要判断原图这里是否是空格子。画画图就知道怎么判断了,很简单,因为坐标基本还是完全对应的。
党的做法是BFS + dij。大致就是,建图,邻接表,每个点和周围四个点相连,然后求最短路。不过木有我的跑得快,嘻嘻。
我这题在zoj排名第四,哈哈~~~
#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <algorithm> using namespace std; const int MAX = 82; int map[MAX][MAX]; int dis[MAX][MAX]; char smap[MAX][MAX]; int dd[MAX][MAX]; int sx,sy,dx,dy; int h,w; int dir[8] = {1,0,-1,0,0,1,0,-1}; void Adj(int x,int y) { if( x <= h && y <= w && x >= 0 && y >= 0 ) map[x][y] = 1; } queue<int> q; void BFS1() { while( !q.empty() ) { int x = q.front(); q.pop(); int y = q.front(); q.pop(); for(int i=0; i<8; i+=2 ) { int a = x + dir[i]; int b = y + dir[i+1]; if( a >= 0 && a <= h && b >= 0 && b <= w && dis[a][b] > dis[x][y] + 1 ) { dis[a][b] = dis[x][y] + 1; q.push(a); q.push(b); } } } } int check(int x1,int y1,int x2,int y2) // 计算两点之间是否可以通过 { int a = max(x1,x2); int b = max(y1,y2); if( smap[a-1][b-1] == '0' ) //因为建图的时候可能有些0的格子被好多1给覆盖掉了 return 1; if( abs( y1 - y2 ) == 1 ) { if( x1 + 1 <= h && x2 + 1 <= h ) if( map[x1+1][y1] == 0 || map[x2+1][y2] == 0 ) return 1; if( x1 - 1 >= 0 && x2 - 1 >= 0 ) if( map[x1-1][y1] == 0 || map[x2-1][y2] == 0 ) return 1; if( x1 - 1 < 0 && x2 - 1 < 0 ) return 1; if( x1 + 1 > h && x2 + 1 > h ) return 1; return 0; } if( abs( x1 - x2 ) == 1 ) { if( y1 + 1 <= w && y2 + 1 <= w ) if( map[x1][y1+1] == 0 || map[x2][y2+1] == 0 ) return 1; if( y1 - 1 >= 0 && y2 - 1 >= 0 ) if( map[x1][y1-1] == 0 || map[x2][y2-1] == 0 ) return 1; if( y1 - 1 < 0 && y2 - 1 < 0 ) return 1; if( y1 + 1 > w && y2 + 1 > w ) return 1; return 0; } } struct NODE{ int x,y,lev; }; bool operator<(NODE a,NODE b) { return a.lev > b.lev; } priority_queue<NODE> Q; int BFS2() { while( !Q.empty() ) { NODE tmp = Q.top(); Q.pop(); int x = tmp.x; int y = tmp.y; int lev = tmp.lev; for(int i=0; i<8; i+=2) { int a = x + dir[i]; int b = y + dir[i+1]; if( a >= 0 && a <= h && b >= 0 && b <= w ) { if( map[a][b] == 1 && map[x][y] == 1 && !check(x,y,a,b) ) continue; if( a == dx && b == dy ) return lev + dis[dx][dy]; if( map[a][b] == 1 && map[x][y] == 1 && check(x,y,a,b) ) { if( lev + dis[a][b] < dd[a][b] ) { tmp.x = a; tmp.y = b; tmp.lev = lev + dis[a][b]; dd[a][b] = lev + dis[a][b]; Q.push(tmp); continue; } } if( lev + dis[a][b] < dd[a][b] ) { tmp.x = a; tmp.y = b; tmp.lev = lev + dis[a][b]; dd[a][b] = lev + dis[a][b]; Q.push(tmp); } } } } return -1; } int main() { int ncases; scanf("%d",&ncases); while( ncases-- ) { while( !Q.empty() ) Q.pop(); memset(map,0,sizeof(map)); memset(dis,0,sizeof(dis)); memset(dd,0,sizeof(dd)); scanf("%d %d",&h,&w); scanf("%d %d %d %d",&sx,&sy,&dx,&dy); for(int i=0; i<h; i++) scanf("%s",smap[i]); for(int i=0; i<h; i++) for(int k=0; k<w; k++) if( smap[i][k] == '1' ) { Adj(i,k); Adj(i,k+1); Adj(i+1,k); Adj(i+1,k+1); } for(int i=0; i<MAX; i++) for(int k=0; k<MAX; k++) dis[i][k] = INT_MAX; for(int i=0; i<=h; i++) for(int k=0; k<=w; k++) { dd[i][k] = INT_MAX; if( map[i][k] ) { q.push(i); q.push(k); dis[i][k] = 0; } } BFS1(); for(int i=0; i<=h; i++) for(int k=0; k<=w; k++) dis[i][k] = w + h - dis[i][k]; NODE tmp; tmp.x = sx; tmp.y = sy; tmp.lev = dis[sx][sy]; dd[sx][sy] = dis[sx][sy]; Q.push(tmp); int ans = BFS2(); if( ans == -1 ) printf("no solution/n"); else printf("%d/n",ans); } return 0; }