SOJ 1041

来源:互联网 发布:oppo手机自动开启数据 编辑:程序博客网 时间:2024/06/05 23:41

1041. Pushing Boxes

Constraints

Time Limit: 1 secs, Memory Limit: 32 MB

Description

Scrap cars in a junk yard are crushed in a device that pushes the car in from the sides, from the front and back, and from the top and bottom. The result is a compact little chunk of metal. In this problem you're going to model a device that works in a similar manner, but doesn't crush anything, only pushes boxes around in two dimensions. The boxes are all square with unit length on a side and are situated on the floor of a room. Each wall of the room can be programmed to move inward a certain amount, pushing any boxes it may bump into. Unlike the car-crusher, this device is sensitive and if it senses that boxes are stacked up against a wall and that it might crush them if pressed any farther, it will stop.

For example, suppose we have boxes arranged in a 12-by-16 room as shown below. The upper left-hand corners of the boxes (which is how we will locate them in this problem) are at coordinates (1,13) (box A below), (3,2), (6,2), (6,4), (6,6), (7,6) and (8,9) (box G), where the first coordinate indicates distance from the top wall and the second coordinate indicates distance from the left wall.

Suppose the top wall is programmed to move down 3 units (then retreats, as the walls always will) and then the right wall is programmed to move left 14 units. The first operation can be performed with no problem, but the second one can not be carried out without crushing some boxes. Therefore, the right wall will move only 13 units, the maximum distance it can move until boxes are packed tightly between it and the left wall. The boxes will then be in the configuration shown in the following figure. The locations of the boxes are (3,1), (3,2), (6,0), (6,1), (6,2), (7,2), (8,2).


Input

There will be multiple data sets for this problem. The first line of each data set will be two integers giving the height and width of the room. (We'll visualize the room as if on a piece of paper, as drawn above.) Each dimension will be no more than 20. The next line will contain an integer n (0 < n <= 10) followed by n pairs of integers, each pair giving the location of a box as the distances from the top and the left walls of the room. The following lines will be of the form direction m, where direction is either down, left, up, right, or done and m is a positive integer. For example, left 2 would mean to try to move the right wall 2 spaces to the left. The "direction" done indicates that you are finished pushing this set of boxes around. There will be no integer m following the direction done, of course. The data sets are followed by a line containing 0 0.

Output

For each data set you are to produce one line of output of the form:

Data set d ends with boxes at locations (r1, c1) (r2, c2) . . . (rn, cn).

where the (ri, ci) are the locations of the boxes given from top-to-bottom, left-to-right, (separated by one space) and d is the data set number (starting at 1).

Sample Input

12 167 1 13 3 2 6 2 6 4 6 6 7 6 8 9down 3left 14done4 43 1 0 2 1 2 3right 3up 2left 1done0 0

Sample Output

Data set 1 ends with boxes at locations (3,1) (3,2) (6,0) (6,1) (6,2) (7,2) (8,2).

Data set 2 ends with boxes at locations (0,2) (1,1) (1,2).

依照题意来模拟推箱子的过程即可,要注意无论向哪个方向移动墙壁,当箱子把墙壁之间顶死了的时候就不能再移动了。

同时有一点题目没有表达的很清楚,当一面墙壁移动到某个位置后要不要恢复原状,我尝试了不恢复结果WA,只有每面墙壁推动后立即复原再推动下一面时才可以AC。

// Problem#: 1041// Submission#: 5062423// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/// All Copyright reserved by Informatic Lab of Sun Yat-sen University#include<iostream>#include<cstring>#include<cmath>using namespace std;#define maxn 20int room[maxn][maxn];//二维数组,有箱子的地方置为1 int ROW,COL,n;//分别保存行数,列数和箱子个数 int rowmax,colmax;//rowmax保存箱子最多的那一行的箱子数,colmax保存箱子最多的那一列的箱子数 int upb,downb,leftb,rightb;//分别保存上下左右四个边界 void saveData()//读取数据确定箱子的位置 {    upb=0;    downb=ROW;    leftb=0;    rightb=COL;    memset(room,0,sizeof(room));    int row,col;     for(int i=0;i<n;++i)    {        cin>>row>>col;        room[row][col]=1;    }} void findMax()//求出rowmax和colmax,求出这两个数可以帮助我们计算墙壁左右移动或者上下移动的最大距离 {    rowmax=-1;    colmax=-1;    for(int i=upb;i<downb;++i)    {        int count=0;        for(int j=leftb;j<rightb;++j)        {            if(room[i][j]) count++;        }        rowmax=max(rowmax,count);    }    for(int j=leftb;j<rightb;++j)    {        int count=0;        for(int i=upb;i<downb;++i)        {            if(room[i][j]) count++;        }        colmax=max(colmax,count);    }}void down(int change)//向下移动 {    if(change>(downb-upb)-colmax) change=downb-upb-colmax;//若移动距离超过了最大距离,则只移动最大距离     int border=upb+change;//移动后墙的位置     for(int i=leftb;i<rightb;++i)    {        for(int j=upb;j<border;++j)//在移动后墙的上方的箱子要全部移到墙的下方         {            if(room[j][i])            {                for(int k=border;k<downb;++k)//为墙上方的箱子在墙下方寻找位置安置,安置原则很简单,在墙下方第一个空置的地方安放即可                 {                    if(!room[k][i])                    {                        room[k][i]=1;                        room[j][i]=0;//原位置已没有箱子,记得设为0                         break;                    }                 }            }        }    }}void up(int change)//同上 {    if(change>downb-upb-colmax) change=downb-upb-colmax;    int border=downb-change;    for(int i=leftb;i<rightb;++i)    {        for(int j=downb-1;j>=border;--j)        {            if(room[j][i])            {                for(int k=border-1;k>=upb;--k)                {                    if(!room[k][i])                    {                        room[k][i]=1;                        room[j][i]=0;                        break;                    }                }            }        }    }}void left(int change)//同上 {    if(change>rightb-leftb-rowmax) change=rightb-leftb-rowmax;    int border=rightb-change;    for(int i=upb;i<downb;++i)    {        for(int j=rightb-1;j>=border;--j)        {            if(room[i][j])            {                for(int k=border-1;k>=leftb;--k)                {                    if(!room[i][k])                     {                        room[i][k]=1;                        room[i][j]=0;                        break;                    }                }            }        }    }}void right(int change)//同上 {    if(change>rightb-leftb-rowmax) change=rightb-leftb-rowmax;    int border=leftb+change;    for(int i=upb;i<downb;++i)    {        for(int j=leftb;j<border;++j)        {            if(room[i][j])            {                for(int k=border;k<rightb;++k)                {                    if(!room[i][k])                    {                        room[i][k]=1;                        room[i][j]=0;                        break;                    }                }            }        }    }}int main(){    int count=1;    while(cin>>ROW>>COL&&ROW&&COL)    {        cin>>n;        saveData();        findMax();        string s;        int change;        while(cin>>s&&s!="done")        {            cin>>change;            if(s=="down") down(change);            else if(s=="up") up(change);            else if(s=="left") left(change);            else right(change);            findMax();//这步很关键,每次移动墙壁后箱子的位置会发生变化,这也使得rowmax和colmax发生变化,所以每次移动后都要更新这两个数据         }        cout<<"Data set "<<count<<" ends with boxes at locations";        for(int i=0;i<ROW;++i)        {            for(int j=0;j<COL;++j)            {                if(room[i][j])                {                    cout<<" "<<'('<<i<<','<<j<<')';                }            }        }        cout<<'.'<<endl;        count++;    }    return 0;}                                 


0 0