CodeForces - 200ACinema模拟题

CodeForces - 200A
Time Limit: 1500MS Memory Limit: 262144KB 64bit IO Format: %I64d & %I64u

 Status

Description

The capital of Berland has the only movie theater in the country. Besides, it consists of only one room. The room is divided into n rows, each row consists of m seats.

There are k people lined up to the box office, each person wants to buy exactly one ticket for his own entertainment. Before the box office started selling tickets, each person found the seat that seemed best for him and remembered it as a pair of coordinates (xi, yi), where xi is the row number, and yi is the seat number in this row.

It is possible that some people have chosen the same place, then when some people see their favorite seat taken in the plan of empty seats in the theater, they choose and buy a ticket to another place. Each of them has the following logic: let's assume that he originally wanted to buy a ticket to seat (x1, y1), then when he comes to the box office, he chooses such empty seat (x2, y2), which satisfies the following conditions:

  • the value of |x1 - x2| + |y1 - y2| is minimum
  • if the choice is not unique, then among the seats that satisfy the first condition, this person selects the one for which the value of x2 is minimum
  • if the choice is still not unique, among the seats that satisfy the first and second conditions, this person selects the one for which the value of y2 is minimum

Your task is to find the coordinates of a seat for each person.

Input

The first input line contains three integers nmk (1 ≤ n, m ≤ 20001 ≤ k ≤ min(n·m, 105) — the number of rows in the room, the number of seats in each row and the number of people in the line, correspondingly. Each of the next k lines contains two integers xiyi (1 ≤ xi ≤ n1 ≤ yi ≤ m) — the coordinates of the seat each person has chosen. Numbers on the same line are separated by a space. The pairs of coordinates are located in the order, in which people stand in the line, starting from the head (the first person in the line who stands in front of the box office) to the tail (the last person in the line).

Output

Print k lines, each containing a pair of integers. Print on the i-th line xi, yi — the coordinates of the seat, for which the person who stands i-th in the line will buy the ticket.

Sample Input

Input
3 4 6
1 1
1 1
1 1
1 2
1 3
1 3
Output
1 1
1 2
2 1
1 3
1 4
2 3
Input
4 3 12
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
Output
2 2
1 2
2 1
2 3
3 2
1 1
1 3
3 1
3 3
4 2
4 1
4 3
 |x1-x2|+|y1-y2| 大家可以理解为横着走多少步,竖着走多少步,加起来就是它的值,现在主要思维是,从一个点开始选择,可能相同的路径已经进行过一次,为了防止超时,我们最主要的工作是减少相同路径重复走几次,如此通过一个d[x][y]表示这个点周围已经走了多少次这里我们要考虑一个情况,就是包围情况,如果一个点的位置在另一个点选择的时候就已经访问了,那么我们就要通过另一个点更新该点
现在讲解这份代码的含义:
for(int i=-1; i<=1; i++) {
            for(int j=-1; j<=1; j++) {
                if(x+i<=0||y+j<=0||x+i>=n||y+j>=m)continue;
                d[x][y]=max(d[x][y],d[x+i][y+j]-abs(i)-abs(j));
        }
}
d[x][y]之前已经说明了,代表着从这个点开始周围的d-1步内都已经被人给选择,不是空位置那么对于d[x][y]与d[x+i][y+j],大家可以画个图,或者是在脑海里思考一下

 
       
如果d[x+i][y+j]为零的,证明d[x][y]与d[x+i][y+j]是没有交集如此得到的肯定还是d[x][y]
因为d[x+i][y+j]-abs(i)-abs(j),这个代表着(x+i,y+j)这个点到(x,y)的距离,这个式子肯定小于零
接着我们思考如果d[x+i][y+j]从(x+i,y+j)这个点开始周围的d-1步内都已经被人给选择,且(x,y)这个点也包括在d-1步内,那么我们可以思考一下,如果这个点已经被访问了,那么可不可以通过其他点的d值得到我这个点最小应该走多少步的d值呢,答案是肯定的,因为如果d[x+i][d+j]步内包括有(x,y)这个点被访问,那么这个点的d[x+i][y+j]值减去abs(i)+abs(j)的值就是他(x,y)周围已经访问了点的最大半径

如此取所有情况的最大值,这里i与j的范围可以自行拟定,因为通过上述说明他的值可以取符合条件的任何值,但是出于时间复杂度的考虑大家可以选择(-1,1),或者是(-2,2),或者是(-3,3)皆可。
代码呈上:
/*
Author: 2486
Memory: 19488 KB		Time: 795 MS
Language: GNU G++ 4.9.2		Result: Accepted
*/

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=2000+5;
bool vis[maxn][maxn];
int d[maxn][maxn];
int n,m,k,ex,ey;
//这个函数的功能是将d转换为行列进行检查,代码大家都懂
bool Check(int x,int y) {
    int l=max(x-d[x][y],1),r=min(x+d[x][y],n);
    for(int i=l; i<=r; i++) {
        int t=d[x][y]-abs(i-x);
        if(y-t>0&&!vis[i][y-t]) {
            ex=i;
            ey=y-t;
            return false;
        }
        if(y+t<=m&&!vis[i][y+t]) {
            ex=i;
            ey=y+t;
            return false;
        }
    }
    return true;
}
int main() {
    //freopen("D://imput.txt","r",stdin);
    int x,y;
    scanf("%d%d%d",&n,&m,&k);
    for(int f=0; f<k; f++) {
        scanf("%d%d",&x,&y);
        if(!vis[x][y]) {
            printf("%d %d\n",x,y);
            vis[x][y]=true;
            continue;
        }
        for(int i=-1; i<=1; i++) {
            for(int j=-1; j<=1; j++) {
                if(x+i<=0||y+j<=0||x+i>=n||y+j>=m)continue;
                d[x][y]=max(d[x][y],d[x+i][y+j]-abs(i)-abs(j));
            }
        }
        while(Check(x,y)) {//接着一步一步往外扩展
            d[x][y]++;
        }
        vis[ex][ey]=true;
        printf("%d %d\n",ex,ey);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值