TZOJ 4471: Postman FJ (二分+bfs)
描述
FJ now is a postman of a small town in the hills. The town can be represented by a N×N matrix. Each field is represented with:
-'K' character: a house;
-'P' character: the post office;
-'.' character: a pasture.
Moreover, each field is assigned with an altitude.
Each day, FJ starts at the single post office of the town, and has to deliver mail to all houses in the town. He can move horizontally, vertically and diagonally to adjacent squares. When he delivers all mails, he must return to the post office.
Now, we define the "tiredness" as the difference between the heights of the highest and the lowest field during the delivering. Tell FJ the minimal tiredness to deliver all the mail.
输入
The first line has an integer N (2 ≤ N ≤ 50), then follows 2*N lines. For the first N lines, each lines has N characters (can be 'P', 'K', '.' characters and 'P' appears exactly once, and 'K' appears at least once) . The next N lines each contain N positive integers indicating the corresponding altitudes of the N*N fields.
Each integer is less than 1000000.
输出
Output one integer indicating the minimum possible tiredness.
样例输入
2
P.
.K
2 1
3 2
样例输出
0
题意:
给一个n*n的矩阵,每个点都有一个高度,图中有一个邮局和若干个房子,求邮递员以邮局为起点途径所有房子并返回起点所经过的点的高度差(最大值-最小值)最小。
邮递员每次可以向周围八个方向移动一格。
题目分析:
首先可以知道只有最多2500个点,我们可以先枚举高度最小值,然后二分它的最大值,二分过程中用bfs判能不能从起点到所有房子。复杂度为:n^4*log(n^2)。
#include <bits/stdc++.h> using namespace std; const int N=55; char s[N][N]; int dx[]={-1,-1,-1,0,0,1,1,1},dy[]={-1,0,1,-1,1,-1,0,1}; vector<int> G[N*N],A,B; int h[N*N],n,S; bool vis[N*N]; bool check(int l,int r) {//判断从起点开始只经过高度[l,r]能否到达所有房子 if(h[S]<l||h[S]>r) return false; for(int i=0;i<n*n;i++) vis[i]=false; queue<int> qu; qu.push(S),vis[S]=true; while(!qu.empty()) { int u=qu.front();qu.pop(); for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(h[v]<l||h[v]>r||vis[v]) continue; qu.push(v),vis[v]=true; } } for(int i=0;i<A.size();i++) { if(!vis[A[i]]) return false; } return true; } int main() { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%s",s[i]); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { scanf("%d",&h[i*n+j]); B.push_back(h[i*n+j]);//存所有的高度 if(s[i][j]=='P') S=i*n+j;//起点 else if(s[i][j]=='K') A.push_back(i*n+j);//存所有的房子 } } for(int i=0;i<n;i++) {//建图 for(int j=0;j<n;j++) { for(int k=0;k<8;k++) { int xx=i+dx[k],yy=j+dy[k]; if(xx<0||xx>=n||yy<0||yy>=n) continue; G[i*n+j].push_back(xx*n+yy); } } } sort(B.begin(),B.end()); int up=B.size(),mn=0x3f3f3f3f; for(int i=0;i<up;i++) {//枚举最小值 int L=i,R=up-1,ans=-1;//二分最大值 while(L<=R) { int mid=(L+R)>>1; if(check(B[i],B[mid])) ans=mid,R=mid-1; else L=mid+1; } if(ans!=-1) mn=min(mn,B[ans]-B[i]); } printf("%d\n",mn); return 0; }