题解 UVA512 【追踪电子表格中的单元格 Spreadsheet Tracking】
WanderingTrader
2020-10-16 22:47:25
思路和汝佳老师的一致,即保存所有操作,每次对单个单元格执行所有操作,不过写法上稍有不同(毕竟没人会用C风格的指针来做吧)。
### 题目分析
我们定义一个结构体 Command 来保存每一条命令:
```cpp
struct Command
{
string cmd;
int n,a[11];
};
```
其中 cmd 表示命令的种类,如果cmd为`EX`,那么四个数分别保存在a[1...4]中。否则用n表示条数,a[1...n]表示数据。
那么基本框架如下:
```cpp
using namespace std;
const int maxn=1e5+5;
int n,q;
struct Command
{
string cmd;
int n,a[11];
};
Command cmds[maxn];
int main()
{
int r,c,kase=0;
while(~scanf("%d%d",&r,&c)&&r)
{
if(kase) printf("\n");
printf("Spreadsheet #%d\n",++kase);
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
cin>>cmds[i].cmd;
if(cmds[i].cmd=="EX")
{
scanf("%d",&cmds[i].a[1]);
scanf("%d",&cmds[i].a[2]);
scanf("%d",&cmds[i].a[3]);
scanf("%d",&cmds[i].a[4]);
}
else
{
scanf("%d",&cmds[i].n);
for(int j=1;j<=cmds[i].n;++j)
scanf("%d",&cmds[i].a[j]);
}
}
scanf("%d",&q);
while(q--)
{
int a,b;
scanf("%d%d",&a,&b);
solve(a,b);
}
}
return 0;
}
```
重点就在于solve函数的实现。
首先我们观察输出中的重复部分:`Cell data in (,)`,所以我们先将其输出,可以减少代码量:
```cpp
void solve(int x,int y)
{
printf("Cell data in (%d,%d) ",x,y);
}
```
接下来遍历每一条语句,如果是`EX`,而且交换的单元格中有当前的x,y,那么执行交换:
```cpp
for(int i=1;i<=n;++i)
{
int cntx=0,cnty=0;
if(cmds[i].cmd=="EX")
{
if(cmds[i].a[1]==x&&cmds[i].a[2]==y)
{
x=cmds[i].a[3];
y=cmds[i].a[4];
}
else if(cmds[i].a[3]==x&&cmds[i].a[4]==y)
{
x=cmds[i].a[1];
y=cmds[i].a[2];
}
}
}
```
否则就遍历该命令中的每一个目标行/列,分情况操作。
注意操作是打包在一起的,所以对x和y的移动要先记录下来,执行完该条命令以后一起操作。
```cpp
else for(int j=1;j<=cmds[i].n;++j)
```
如果命令为`DR`,那么若被删除的行号u=x,则直接输出`GONE`并退出,若u<x,那么x对应的行会往上一个,x减一:
```cpp
if(cmds[i].cmd=="DR")
{
if(cmds[i].a[j]==x)
{
printf("GONE\n");
return;
}
else if(cmds[i].a[j]<x)
--cntx;
}
```
`DC`与`DR`几乎完全一样,只是把x换成了y而已:
```cpp
else if(cmds[i].cmd=="DC")
{
if(cmds[i].a[j]==y)
{
printf("GONE\n");
return;
}
else if(cmds[i].a[j]<y) --cnty;
}
```
如果是`IR`,那么如果被添加的行u<=x(注意u=x的时候也是),就把x加一,`IC`同理:
```cpp
else if(cmds[i].cmd=="IR")
{
if(cmds[i].a[j]<=x) ++cntx;
}
else if(cmds[i].a[j]<=y) ++cnty;
```
执行完一整条语句后把x,y做对应的修改即可:
```cpp
x+=cntx;y+=cnty;
```
最后打印出移动后的位置:
```cpp
printf("moved to (%d,%d)\n",x,y);
```
solve函数完整代码如下:
```cpp
void solve(int x,int y)
{
printf("Cell data in (%d,%d) ",x,y);
for(int i=1;i<=n;++i)
{
int cntx=0,cnty=0;
if(cmds[i].cmd=="EX")
{
if(cmds[i].a[1]==x&&cmds[i].a[2]==y)
{
x=cmds[i].a[3];
y=cmds[i].a[4];
}
else if(cmds[i].a[3]==x&&cmds[i].a[4]==y)
{
x=cmds[i].a[1];
y=cmds[i].a[2];
}
}
else for(int j=1;j<=cmds[i].n;++j)
{
if(cmds[i].cmd=="DR")
{
if(cmds[i].a[j]==x)
{
printf("GONE\n");
return;
}
else if(cmds[i].a[j]<x) --cntx;
}
else if(cmds[i].cmd=="DC")
{
if(cmds[i].a[j]==y)
{
printf("GONE\n");
return;
}
else if(cmds[i].a[j]<y) --cnty;
}
else if(cmds[i].cmd=="IR")
{
if(cmds[i].a[j]<=x) ++cntx;
}
else if(cmds[i].a[j]<=y) ++cnty;
}
x+=cntx;y+=cnty;
}
printf("moved to (%d,%d)\n",x,y);
}
```
注意,本题的输出需要在 **第二组及以后的表格之前输出一个空行**。
模拟题考的还是耐心,要能静下心来调错。
$$\texttt{The End.}$$