POJ 2922 Honeymoon Hike (二分+枚举)

来源:http://poj.org/problem?id=2922

题意:给出一张N x N的地图,找出一条从左上角到右下角的路径,使得该路径上的【最大值】- 【最小值】结果最小,输出该结果。

分析:该地图规模最大为100 x 100,如果直接暴力搜索,我们必须对每条可能的路径进行搜索,才能得出正确的结果,时间复杂度为O(410000),一定会超时。所以,我们只能寻求其他的切入点。

   我们试着这样去分析问题,我们很难直接地在搜索中使用剪枝,而我们最终要得到的是一个差值,这个差值的区间在【0,200】,由路径中的最大值与最小值得出。把问题分析到这里,我们考虑是否可以通过枚举差值,通过这个差值去找到对应的上界与下界的集合。判断题目给的图是否满足我们所枚举的条件,通过这样的方式得到的一个可满足我们刚才提到的条件的最小差值,就是我们需要的答案。同时,我们也解决了原图难以剪枝的问题,判断该图是否满足条件,只要把最大值/最小值越过上下界的路给剪掉即可,搜一次图的成本为O(n2)

   考虑到这里还不够,这道题依然会超时,因为200个差值一一枚举还是太多了,我们要想办法优化某些流程。刚好,我们眼前的这个区间就很好下手,我们由此不难想到二分法,通过二分去找一个差值,我们可以将差值的枚举量降为log(200),到这里,问题就已经解决了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 
 5 using namespace std;
 6 
 7 int Mx[4] = {1,0,-1,0};
 8 int My[4] = {0,1,0,-1};
 9 
10 struct Node {
11     int x,y,min,max;
12     
13     Node(int x, int y, int min, int max):x(x),y(y),min(min),max(max){}
14 };
15 
16 int n;
17 int Maze[100][100];
18 bool vis[100][100];
19 
20 bool isAvailable(int x) {
21     for (int lower=0;lower+x<=200;lower++) {
22         memset(vis,0,sizeof(vis));
23         queue<Node> Q;
24         Q.push(Node(0,0,Maze[0][0],Maze[0][0]));
25         if (Maze[0][0] < lower || Maze[0][0] > lower+x)
26             continue;
27         vis[0][0] = 1;
28         while (!Q.empty()) {
29             Node p = Q.front();
30             Q.pop();
31             for (int i=0;i<4;i++) {
32                 int xx = p.x + Mx[i];
33                 int yy = p.y + My[i];
34                 
35                 if (xx < 0 || yy  < 0 || xx == n || yy == n || vis[xx][yy])
36                     continue;
37                 if (Maze[xx][yy] < lower || Maze[xx][yy] > lower+x)
38                     continue;
39                 if (xx == n-1 && yy == n-1)
40                     return true;
41                 vis[xx][yy] = 1;
42                 Q.push(Node(xx,yy,min(p.min,Maze[xx][yy]),max(p.max,Maze[xx][yy])));
43             }
44         }
45     }
46     return false;
47 }
48 
49 int main() {
50     int t,cas = 1;
51     scanf("%d",&t);
52     
53     while (t--) {
54         scanf("%d",&n);
55         for (int i=0;i<n;i++) {
56             for (int j=0;j<n;j++) {
57                 scanf("%d",&Maze[i][j]);
58             }
59         }
60         int L = 0, R = 200;
61         while (L < R) {
62             int mid = (L+R)/2;
63             if (isAvailable(mid)) {
64                 R = mid;
65             } else {
66                 L = mid + 1;
67             }
68         }
69         printf("Scenario #%d:\n%d\n\n",cas++,R);
70     }
71     
72     return 0;
73 }
View Code
 

猜你喜欢

转载自www.cnblogs.com/doublebit/p/10829119.html