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