本着清晰明了易懂可以水两篇 的理念,笔者将这道题分两次发布。这是第二种解法。
第一种解法传送门→解法一+提交网址
因为解法1中有详细关于题目和输入输出格式等的介绍,这里就不过多赘述了。
分析:
一些初学者做题的主要思路都是解法1:将题中每个可能的操作都考虑到,确保计算出所有可能的所有结果。
但解法2的思路相比上述有很大不同。
这个思路是将所有操作保存,然后对于每个查询重新执行每个操作,但不需要计算整个电子表格的变化,而只需关注所查询的单元格的位置变化。不仅更好写,且效率更高。
换句话说:我们的目标是解决问题,而不是为了写程序而写程序,同时应保持简单,而不是自己创造条件去展示编程技巧。
思路:
循环1:输入3变量,r,c,n,进入n个循环
循环2:输入操作类型s、若为交换,则输入4变量。若为其他,则输入行/列数,保存到数组。
还是循环2:输入num个坐标,进入函数,先解决交换(Easy),若为插入,且插入行在坐标行的前面,则最后输出坐标的行数+1,如果插入行等于坐标行,则返回GONE; 若为删除,且删除行在坐标行前面,则最后输出的坐标数减1;
返回,输出。
代码:
#include<stdio.h>
#include<string.h>
#define maxd 10000
struct Command{
char c[5];//保存指令
int r1, c1, r2, c2;//交换的两个坐标
int a, x[20];// a 为当前指令行列变换操作次数 x[20] 存储的是相应指令集合
}cmd[maxd];
int r, c, n; //n为指令次数
int simulate(int *r0, int *c0){
for(int i = 0; i < n; i++ ){
if(cmd[i].c[0] == 'E'){//交换操作
if(*r0 == cmd[i].r1 && *c0 == cmd[i].c1){
*r0 = cmd[i].r2;
*c0 = cmd[i].c2;
}
else if(*r0 == cmd[i].r2 && *c0 == cmd[i].c2){
*r0 = cmd[i].r1;
*c0 = cmd[i].c1;
}
}
else if(cmd[i].c[0] != 'E'){
int dr = 0,dc = 0;//记录每组此操作r0, c0坐标变换情况
for(int j = 0; j < cmd[i].a; j++ ){
int x = cmd[i].x[j];
if(cmd[i].c[0] == 'I'){
if(cmd[i].c[1] == 'R' && x <= *r0 ) dr++;//(需要插入当前行、列前面
if(cmd[i].c[1] == 'C' && x <= *c0) dc++;//才会影响r0, c0)
}
else if(cmd[i].c[0] == 'D'){
if(cmd[i].c[1] == 'R' && x == *r0) return 0;//删除当前行、列
if(cmd[i].c[1] == 'C' && x == *c0) return 0;//时直接返回 0
if(cmd[i].c[1] == 'R' && x < *r0) dr--;(同上注意删除不能是本行列)
if(cmd[i].c[1] == 'C' && x < *c0) dc--;
}
}
*r0 += dr;//每组指令执行完毕后 更新此时 坐标状况
*c0 += dc;
}
}
return 1;
}
int main()
{
// freopen("C:\\Users\\zhangwei\\Desktop\\input.txt","r",stdin);
int r0, c0, q, kcase = 0;
while(scanf("%d%d%d",&r,&c,&n) == 3 && r != 0){
for(int i = 0; i < n; i++ ){
scanf("%s",cmd[i].c);
if(cmd[i].c[0] == 'E'){
scanf("%d%d%d%d",&cmd[i].r1,&cmd[i].c1,&cmd[i].r2,&cmd[i].c2);
}
else{
scanf("%d",&cmd[i].a);
for(int j = 0; j < cmd[i].a; j++ ){
scanf("%d",&cmd[i].x[j]);
}
}
}
if(kcase++)
printf("\n");
printf("Spreadsheet #%d\n",kcase);
scanf("%d",&q);
while(q--){
scanf("%d%d",&r0, &c0);
printf("Cell data in (%d,%d) ", r0, c0);
if(!simulate(&r0, &c0))
printf("GONE\n");
else
printf("moved to (%d,%d)\n", r0, c0);
}
}
return 0;
}
收获:
本题告诉我们,我们最终的目的是解题,而不是通盘考虑去展现算法技巧,所以我们只需关注与问题有关的变量,并将其过程化。
结语:
我们的目标是解决问题,而不是为了写程序而写程序,同时应保持简单,而不是自己创造条件去展示编程技巧。