意甲冠军:给定一个N*M图。,间‘X’代表树木(树木必须汇集到森林,非分离),然后,‘.’它代表的空间。‘*’它代表的起点。现在它需要从起点。一圈,最后回到起点,所经过最少点数。
题目中给的‘+’就是当中一种最短路径。
题解:随便找一条经过森林且不经过起点的直线,可证路径一定会穿过这条直线。那么就在这条直线上枚举一个点,做两遍BFS,求其从分别直线两側出发到起点的最短距离。
在这里说一个推断边界的简单方法,就是先给图里每一个点打上标记。详见代码里‘in’数组。in值为0的自然就不再里面,而没有必要推断什么“1<=x&&x<=n&&……”。
好了,贴代码。
#include <queue> #include <cstdio> #include <cstring> #include <algorithm> #define N 55 #define inf 0x3f3f3f3f using namespace std; const int dx[8]={-1,-1,-1,0,0,1,1,1}; const int dy[8]={-1,0,1,-1,1,-1,0,1}; struct Lux { int x,y; Lux(int a,int b):x(a),y(b){} Lux(){} }; char mp[N][N]; int map[N][N];/*0可行,1森林,2枚举线段,3起点*/ int n,m,ans=inf; int dist[N][N],tx,ty; int in[N][N],cnt; queue<Lux>q; int bfs(int sx,int sy) { int i,fr,ret; int vx,vy; for(ret=fr=0;fr<2;fr++) { memset(dist,0x3f,sizeof(dist)); while(!q.empty())q.pop(); for(i=fr*5;i<fr*5+3;i++) { vx=sx+dx[i]; vy=sy+dy[i]; if(in[vx][vy]&&!map[vx][vy])dist[vx][vy]=1,q.push(Lux(vx,vy)); } while(!q.empty()) { Lux U=q.front();q.pop(); for(i=0;i<8;i++) { vx=U.x+dx[i]; vy=U.y+dy[i]; if(in[vx][vy]&&!map[vx][vy]&&dist[vx][vy]>dist[U.x][U.y]+1) { dist[vx][vy]=dist[U.x][U.y]+1; q.push(Lux(vx,vy)); } } } ret+=dist[tx][ty]; } return ret; } int main() { // freopen("test.in","r",stdin); int i,j,x,y; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%s",mp[i]+1); for(j=1;j<=m;j++)for(i=1;i<=n;i++) { in[i][j]=++cnt; if(mp[i][j]=='X') { map[i][j]=1; x=i;y=j; } else if(mp[i][j]=='*')tx=i,ty=j; } if(tx==x&&ty>y) { for(i=y;mp[x][i]=='X';i--); y=i; for(i=y;i;i--)map[x][i]=3; for(i=y;i;i--)ans=max(ans,bfs(x,i)); } else { for(i=y+1;i<=m;i++)map[x][i]=3; for(i=y+1;i<=m;i++)ans=min(ans,bfs(x,i)); } printf("%d ",ans); return 0; }
版权声明:本文博主原创文章,博客,未经同意不得转载。