| 
		
			| 
	
	
		
			  /**//* 
  题意: n*m的网格,一些网格有Light,Light有level ,能照射上下左右最多level个(包括自身) 
  现要设定一个最小的level,使得小于该level的Light都关掉,大于的都调整到该level,使得任意一个格子 
  要么自身有Light,要么竖直、水平方向都必须被灯照到 
  
  这题一开始想到的是计算每个格子能满足条件的最小level,然后在这些level中取最大 
  这样子有问题,因为这样子认定了若level0能被照到,则>level0的也能被照到,如 
  5  0  0 
  0  2  0 
  0  0  5 
  
  考虑每个格子的话,他能被覆盖的level,是一段一段的值,如[1,3] , [5,7]  
  这样子是比较复杂的,答案会是每个格子可选的范围的交集 
  
  Email了两个人,非常感谢了: 【bupt】xiaofan  ,   Navi 
  做法是: 
  对每个Light记录它4个方向邻接的Light 
  一开始假设所有Light都亮,计算每相邻Light要覆盖他们之间的格子的值,即两个距离/2,取所有这些值的最大 
  以这个为起点(答案至少是这个) , 然后对小于这个level的Light都去掉,O(1)更新被影响到的邻接Light 
  然后这样子不断增大的去枚举 , 发现不能覆盖完就No Answer 
  否则某个level值可以覆盖所有格子,而且不用再熄Light就是答案了 
  
  这里为了去掉小于Level的Light,先排序 
  */ 
  #include<cstdio> 
  #include<cstring> 
  #include<algorithm> 
  #include<vector> 
  #include<queue> 
  #include<map> 
  #include<cmath> 
  #include<cstdlib> 
  #include<iostream> 
  
  using namespace std; 
  
  const int INF = 1000000000; 
  const int MAXN = 10010; 
  
  
  struct Light 
    { 
  int x, y , level; 
  int next[4]; // left  up  right  down 
   Light()  {} 
  Light(int _x, int _y , int _level) 
     { 
  x = _x; 
  y = _y; 
  level = _level; 
  for(int i = 0; i < 4 ; i++) 
  next[i] = -1; 
  } 
  bool operator < ( const Light &B )const 
     { 
  return level < B.level; 
  } 
  void update(); 
  }; 
  
  int n , m , ans; 
  int a[110][10086]; 
  Light light[110*10086]; 
  
  void Light:: update()//去掉该Light后    O(1)更新  邻接的Light ,  覆盖相邻Light之间格子的距离 
    { 
  int left = next[0] ; 
  int right = next[2]; 
  if(left != -1) light[left].next[2] = right; 
  if(right != -1)light[right].next[0] = left; 
  
   if(left == -1 && right == -1 )ans = INF;/**///////// 
  else if(left == -1 )ans = max(ans , light[right].y); 
  else if(right == -1)ans = max(ans , m-light[left].y+1); 
  else ans = max(ans , (light[right].y - light[left].y +2 )/2); 
  
  int up = next[1]; 
  int down = next[3]; 
  if(up != -1)light[up].next[3] = down; 
  if(down != -1)light[down].next[1] = up; 
   
  if(up==-1 && down ==-1)ans = INF; 
  else if(up==-1)ans = max(ans,light[down].x); 
  else if(down == -1)ans = max(ans , n-light[up].x+1); 
  else ans = max(ans , (light[down].x - light[up].x+2)/2); 
  } 
  
  int main() 
    { 
  
  #ifdef ONLINE_JUDGE 
  #else 
  freopen("in", "r", stdin); 
  #endif 
  
  while( scanf("%d%d",&n,&m) , n || m) 
     { 
  int tot = 0; 
  for(int i = 1; i <= n; i ++) 
  for(int j = 1 ; j <= m ; j++) 
     { 
  scanf("%d",&a[i][j]); 
  if(a[i][j]) 
     { 
  light[++tot] = Light(i,j,a[i][j]); 
  } 
  } 
  
  sort( light + 1 , light + 1 + tot); 
  for(int i = 1 ; i <= tot ; i++) 
  a[light[i].x][light[i].y] = i;            //记录为id 
  
  ans = 0; 
  
  //left right 
  for(int i = 1 ; i <= n && ans != INF ; i++) 
     { 
  int pre = -1; 
  for(int j = 1;  j <= m; j++) 
     { 
  if(a[i][j])//a[i][j] 存的是在 light[]中的位置 
     { 
  if(pre==-1)ans = max(ans , j); 
  else 
     { 
  ans = max(ans , (j-pre+2)/2); 
  light[a[i][j]].next[0] = a[i][pre]; 
  light[a[i][pre]].next[2] = a[i][j]; 
  } 
  pre = j; 
  } 
  } 
  if(pre == -1)ans = INF; 
  else ans = max(ans,m-pre+1); 
  } 
  
  //up down 
  for(int j = 1 ; j <= m && ans != INF ; j++) 
     { 
  int pre = -1; 
  for(int i = 1;  i <= n; i++) 
     { 
  if(a[i][j]) 
     { 
  if(pre==-1)ans = max(ans , i); 
  else 
     { 
  ans = max(ans , (i-pre+2)/2); 
  light[a[i][j]].next[1] = a[pre][j]; 
  light[a[pre][j]].next[3] = a[i][j]; 
  } 
  pre = i; 
  } 
  } 
  if(pre == -1)ans = INF; 
  else ans = max(ans,n-pre+1); 
  
  } 
  int p = 1 ; 
  while( ans < INF && p <= tot && light[p].level < ans ) 
  light[p++].update(); 
  if(ans == INF)puts("NO ANSWER!"); 
  else printf("%d\n",ans); 
  } 
  
  return 0; 
  } 
  
      
	    
    
 |  | 
		
			| 常用链接随笔分类Links搜索最新评论
	
 |  |