 /**//*
题意: 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
搜索
最新评论

|
|