参考了一下学长们的代码终于过了= =
题面如下:
恩第一次看大概都会以为测控站控制的是一个平面,然而实际上只是控制一条线上的点。但测控站只能在标记为1的点上建站,而且左边m行上的中间必须建站,难度似乎高了不少,然而其实这一个条件就能把整道题变成水题。
因为东半球的赤道上必须建站,那么题面上就给你提供了开始查找的点,那么这样的话就可以建立由一个一条线上可建立的测控站的点构成的数组,而且这个数组的开端和终点均会为东半球上,然后的方法还是二分枚举,所查找的还是半径。但二分时的判断有一定的难度,需要一定的思考。下面给出代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; int a[1010][2010],m,n,k,ce[2010],tmp[2010],top; char ch[1010][2010]; bool check(int r)//判断 { int sum=1,f=ce[1]+r;//sum为用到的备用点的数量,f为当前测控站向前延伸的最大范围 for (int i=2;i<=top;i++) { while (ce[i]-r>f+1)//如果当前备用点在当前测控站测控的范围之外,进行判断 { if (ce[i-1]+r==f) return false;//如果当前所查找的备用点的前一点恰好为当前所用到的测控站,即没有备用点的使用能够满足题意时返回false sum++;//用到的点的总和加1(因为进入while循环时前一点必定在测控范围内) f=ce[i-1]+r; } } if (sum>k) return false; return true;//如果用到的测控站的数目超过要求的最大数目,返回false,否则返回true } void work()//二分查找 { int l=0,r=(n-1)/2,mid; while (l+1<r) { mid=(l+r)/2; if (check(mid)) r=mid; else l=mid; } if (check(l)) printf("%d ",l); else printf("%d ",r); } int main() { freopen("add.in","r",stdin); freopen("add.out","w",stdout); scanf("%d %d %d",&n,&m,&k); for (int i=1;i<=n;i++){ for (int j=1;j<=m*2;j++) { scanf("%c",&ch[i][j]); while (ch[i][j]!='0'&&ch[i][j]!='1') scanf("%c",&ch[i][j]); a[i][j]=ch[i][j]-'0'; } //cout<<ch[i]<<endl; } for (int i=1;i<=m;i++){ top=0; for (int j=n/2+1;j<=n;j++) if (a[j][i]==1) ce[++top]=j-n/2; for (int j=n;j>=1;j--) if (a[j][i+m]==1) ce[++top]=n-j+1+n/2+1; for (int j=1;j<=n/2+1;j++) if (a[j][i]==1) ce[++top]=j+n+n/2+1;//将所有可能建立测控站的点建立起一个数组,且这个数组的开端与顶点均为东半球赤道上的点(但这一点的表示方法不同),此时所得到的数组必定有序 work(); } return 0; }