http://codeforces.com/problemset/problem/200/A
好题,虽然我又没独立想出来=。=。。给一个n*m的点矩阵,询问K次,每个输入一个坐标x,y,寻找一个于该坐标曼哈顿距离最小且未被占有的点,并占有它。
做法是每次询问从x开始往左右暴力枚举横坐标,直到横坐标绝对值差已经大于当前答案。可以保证第i个询问,最多只需要向两边枚举sqrt(i)次。同时可以利用并查集,对于每个横坐标O(1)求出最接近的点。。最后当n比m大很多时候算法会退化,此时可以通过交换横竖坐标来解决。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 //By Lin 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 2005 6 #define inf 0x7fffffff 7 using namespace std; 8 9 bool flag = false; 10 int n,m,K; 11 int up[maxn][maxn],down[maxn][maxn]; 12 int Find(int p[],int x){ 13 return p[x] != x?p[x]=Find(p,p[x]):x; 14 } 15 16 void check(int x,int y,int i,int &g,int &h ,int &L ){ 17 if ( i < 1 || i > n ) return; 18 int j; 19 j = Find(up[i],y); 20 if ( j != 0 ) { 21 int d = abs(x-i)+abs(y-j); 22 if ( d < L || d == L && ( !flag&&(i<g || i==g && j<h ) || flag&&(j<h || j==h && i<g ) ) ) 23 L = d , g = i , h = j; 24 } 25 j = Find(down[i],y); 26 if ( j != m+1 ) { 27 int d = abs(x-i)+abs(y-j); 28 if ( d < L || d == L && ( !flag&&(i<g || i==g && j<h ) || flag&&(j<h || j==h && i<g ) ) ) 29 L = d , g = i , h = j; 30 } 31 } 32 33 int main(){ 34 scanf("%d%d%d", &n, &m , &K ); 35 if ( n > m ) { 36 swap(n,m); 37 flag = true; 38 } 39 for (int i = 1; i<=n; i++) 40 for (int j = 0; j<=m+1; j++) up[i][j] = down[i][j] = j; 41 while ( K -- ){ 42 int x , y; 43 scanf("%d%d", &x, &y ); 44 if ( flag ) swap(x,y); 45 int g = -1 , h = -1 , L = inf; 46 for (int i = 0; i<=L; i++){ 47 check( x , y , x-i , g , h , L ); 48 check( x , y , x+i , g , h , L ); 49 } 50 up[g][h] = h-1; 51 down[g][h] = h+1; 52 if ( flag ) swap(g,h); 53 printf("%d %d\n" , g , h ); 54 } 55 return 0; 56 }