 /**//*
題意: 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
搜索
最新評論

|
|