2910 -- 【模拟试题】飞船监控站
Description
“神州七号”飞船已经圆满发射成功了,你可知道飞船的顺利运行离不开地面对其的测控吗?因而必须保证飞船运行的轨道被测控站的雷达所全部覆盖,才能正常接受和传输信号。而由于测控站所控制的范围越小,信号接收情况越好,技术难度也越低。所以我们希望在覆盖整个轨道的前提下,使得测控站所需控制的范围越小越好。由于条件限制,最多只能建立K个测控范围相同的测控站,而且并不是任何位置都可以建立测控站的,所以需要找出一种方案,使得所需测控的范围尽量小。虽然离真正的模型还有一定差距,但喜欢编程的你当然对此问题跃跃欲试了。
为了你的方便,已经帮你把地球抽象展开成一个N*2M的平面矩阵(N为奇数)。其中前M列是东半球,后M列是西半球,最中间的一行为赤道。为了简化问题,飞船的轨道可以看作是在一条穿越东西半球的经线上空(虽然实际并非如此),在此矩阵表示为第I列和第I+M列(1<=I<=M)两端对接形成的一个环。矩阵的每一个格子中可以建立一个监测站,但某些格子除外(比如其他国家的领土或是条件恶劣的地区)。假设测控半径为R,则每个测控站的控制范围可以向上向下各延伸R个格子,即总长度为2R+1的区间。测控范围的重叠并不会相互影响,并且显然有R>=0且2R+1<=N(因为地球是圆的,测控范围最多只能是一个半球)。
由于飞船有M条可选轨道,所以需要你计算出对于每条轨道,最小的测控半径是多少。注意由于控制的需要,对于任意一条轨道,在东半球的赤道上都必须建立一个测控站,并且保证在东半球的赤道上建站不会有限制。
Input
输入的第一行为三个正整数N,M,K表示矩阵的大小以及测控站的数量。保证有(2<=N,M<=1000,2<=K<=2N,N为奇数)。接下来N行,每行2M个字符,如果是1则表示可以放置测控站,否则为0表示无法放置。(保证中间一行的前M个字符一定为1)
Output
输出包含M行,每行包含一个正整数,第I行表示第I条轨道所需最小的测控半径R为多少(保证必然有解),轨道从左到右依次编号。
Sample Input
5 2 4
0110
0000
1100
0011
1000
Sample Output
1
2
Hint
【样例解释】
对于轨道1:从第一行第一列开始向下可以展开为0010101001(首尾相连)
对于轨道2:从第一行第二列开始向下可以展开为1010001000(首尾相连)
两条轨道均把可选点全部建站即可。
【数据范围】
对于30%的数据,有N,M<=15
对于60%的数据,有N,M<=100
Description
“神州七号”飞船已经圆满发射成功了,你可知道飞船的顺利运行离不开地面对其的测控吗?因而必须保证飞船运行的轨道被测控站的雷达所全部覆盖,才能正常接受和传输信号。而由于测控站所控制的范围越小,信号接收情况越好,技术难度也越低。所以我们希望在覆盖整个轨道的前提下,使得测控站所需控制的范围越小越好。由于条件限制,最多只能建立K个测控范围相同的测控站,而且并不是任何位置都可以建立测控站的,所以需要找出一种方案,使得所需测控的范围尽量小。虽然离真正的模型还有一定差距,但喜欢编程的你当然对此问题跃跃欲试了。
为了你的方便,已经帮你把地球抽象展开成一个N*2M的平面矩阵(N为奇数)。其中前M列是东半球,后M列是西半球,最中间的一行为赤道。为了简化问题,飞船的轨道可以看作是在一条穿越东西半球的经线上空(虽然实际并非如此),在此矩阵表示为第I列和第I+M列(1<=I<=M)两端对接形成的一个环。矩阵的每一个格子中可以建立一个监测站,但某些格子除外(比如其他国家的领土或是条件恶劣的地区)。假设测控半径为R,则每个测控站的控制范围可以向上向下各延伸R个格子,即总长度为2R+1的区间。测控范围的重叠并不会相互影响,并且显然有R>=0且2R+1<=N(因为地球是圆的,测控范围最多只能是一个半球)。
由于飞船有M条可选轨道,所以需要你计算出对于每条轨道,最小的测控半径是多少。注意由于控制的需要,对于任意一条轨道,在东半球的赤道上都必须建立一个测控站,并且保证在东半球的赤道上建站不会有限制。
Input
输入的第一行为三个正整数N,M,K表示矩阵的大小以及测控站的数量。保证有(2<=N,M<=1000,2<=K<=2N,N为奇数)。接下来N行,每行2M个字符,如果是1则表示可以放置测控站,否则为0表示无法放置。(保证中间一行的前M个字符一定为1)
Output
输出包含M行,每行包含一个正整数,第I行表示第I条轨道所需最小的测控半径R为多少(保证必然有解),轨道从左到右依次编号。
Sample Input
5 2 4
0110
0000
1100
0011
1000
Sample Output
1
2
Hint
【样例解释】
对于轨道1:从第一行第一列开始向下可以展开为0010101001(首尾相连)
对于轨道2:从第一行第二列开始向下可以展开为1010001000(首尾相连)
两条轨道均把可选点全部建站即可。
【数据范围】
对于30%的数据,有N,M<=15
对于60%的数据,有N,M<=100
对于100%的数据,有N,M<=1000
可以看出R的变化对答案的影响是不降的,也就是可以用二分。
二分覆盖范围R,样例非常良心,直接把check的重要部分告诉了,把两条经线复制到一起,线段覆盖即可。
..其实这个线段覆盖还没这么简单,不同于朴素的贪心线段覆盖,这个线段覆盖稍微难一点,毕竟是个环..
注意到这tm是个环,所有往左往右的时候不能直接++,--了,注意判边界。
贪心策略:
注意性质:必须要把所有点覆盖完,我们从赤道开始(题目)覆盖,在这个点之前的保证全部覆盖完毕。
对于一个点,先看右边的轨道中有没有观察站能够覆盖到当前点,这个观察站越远越好,因为当前点左边的都被覆盖完了,尽量减少重复。
如果右侧没有可选的点,如果当前点可用,使用当前点。
还没有,就要从左边搜,这个观察站越近越好,因为要尽量往右边贡献。
一轮扫下来,如果不能覆盖,就返回0.
- -调半天90分WA,对拍标程发现竟然有R=0的数据.然而二分下界定的1,这就很尴尬了..
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
//#include<cmath>
using namespace std;
inline int read()
{
int bj=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')bj=-1;
ch=getchar();
}
int ret=0;
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
return ret*bj;
}
int n,m,k,map[2005][2005]={0},a[4005]={0};
bool vis[4005]={0};
void init()
{
n=read();m=read();k=read();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=2*m;j++)
{
char ch;
cin>>ch;
map[i][j]=ch-'0';
}
}
}
void orbit(int idx)
{
a[0]=0;
for(int i=1;i<=n;i++)a[++a[0]]=map[i][idx];
for(int i=n;i;i--)a[++a[0]]=map[i][idx+m];
}
int L(int x,int R)
{
int pos=x-R,lim=2*n;
pos+=lim;
if(pos%lim==0)return lim;
return pos%lim;
}
int R(int x,int R)
{
int pos=x+R,lim=2*n;
if(pos%lim==0)return lim;
return pos%lim;
}
void cover(int x,int r)
{
for(int i=0;i<=r;i++)vis[L(x,i)]=vis[R(x,i)]=1;
}
bool check(int r)
{
memset(vis,0,sizeof(vis));
int st=(n+1)/2,ans=1;
cover(st,r);
int pos=R(st,r+1);
while(pos!=st)
{
//if(r==2)cout<<pos<<"<----\n";
if(vis[pos])
{
pos=R(pos,1);
continue;
}
bool fl=0;
for(int j=r;j;j--)
{
if(a[R(pos,j)]==1)
{
fl=1;
ans++;
cover(R(pos,j),r);
break;
}
}
if(fl)continue;
if(a[pos]==1)
{
fl=1;
ans++;
cover(pos,r);
}
if(fl)continue;
for(int j=1;j<=r;j++)
{
if(a[L(pos,j)]==1)
{
fl=1;
ans++;
cover(L(pos,j),r);
break;
}
}
if(fl)continue;
return 0;
}
return ans<=k;
}
void Binary_Search()
{
int l=0,r=2*n+1,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
printf("%d\n",ans);
}
void work()
{
for(int i=1;i<=m;i++)
{
orbit(i);
Binary_Search();
}
}
int main()
{
init();
work();
return 0;
}