题目意思就是对电子表格进行一系列操作后追踪各cell的去向,基本操作类型有EX DR DC IR IC 5种,注意一个操作可能包含多个同时进行的子操作
sample input
7 9 5 DR 2 1 5 DC 4 3 6 7 9 IC 1 3 IR 2 2 4 EX 1 2 6 5 4 4 8 5 5 7 8 6 5 0 0
sample output
Spreadsheet #1
Cell data in (4,8) moved to (4,6) Cell data in (5,5) GONE Cell data in (7,8) moved to (7,6) Cell data in (6,5) moved to (1,2)
思路一,输出最终表格,在表格中查询原始cell,输出新坐标
我的理解是每次重新操作时的指令都是针对当前表格,但好像与题意有点出入,最后结果不一样,最终程序写得非常繁琐,首先定义一个copy函数,这是5个操作函数的基础,然后考虑主程序,指令判断用了5个基本一样的if分支,由于语句类似,直接复制粘贴。。
下面是源码
#include<iostream> const int maxn = 50; int s[maxn][maxn]; int r, c; void EX(int a, int b, int c, int d); void copy(char type, int p, int q); void DR(int n); void DC(int n); void IR(int n); void IC(int n); int main() { using namespace std; cin >> r >> c; for (int i = 0; i < maxn; i++) { for (int j = 0; j < maxn; j++) s[i][j] = 0; } for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) s[i][j] = (i + 1) * 10 + j + 1; } int count; cin >> count; while (count--) { char operation[3]; cin >> operation; if (operation[0]=='E') { int a, b, c, d; cin >> a >> b >> c >> d; EX(a, b, c, d); } else if (operation[0] == 'D'&&operation[1] == 'R') { int m; cin >> m; int* op = new int[m]; for (int i = 0; i < m; i++) cin >> op[i]; for (int i = 0; i<m; i++) { int k = 0; for (int j = 0; j < i; j++) if (op[j] < op[i])k++; DR(op[i] - k); } delete[]op; } else if (operation[0] == 'D'&&operation[1] == 'C') { int m; cin >> m; int* op = new int[m]; for (int i = 0; i < m; i++) cin >> op[i]; for (int i = 0; i<m; i++) { int k = 0; for (int j = 0; j < i; j++) if (op[j] < op[i])k++; DC(op[i]-k); } delete[]op; } else if (operation[0] == 'I'&&operation[1] == 'R') { int m; cin >> m; int* op = new int[m]; for (int i = 0; i < m; i++) cin >> op[i]; for (int i = 0; i<m; i++) { int k = 0; for (int j = 0; j < i; j++) if (op[j] < op[i])k++; IR(op[i] + k); } delete[]op; } else if (operation[0] == 'I'&&operation[1] == 'C') { int m; cin >> m; int* op = new int[m]; for (int i = 0; i < m; i++) cin >> op[i]; for (int i = 0; i<m; i++) { int k = 0; for (int j = 0; j < i; j++) if (op[j] < op[i])k++; IC(op[i] + k); } delete[]op; } /*for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) cout << s[i][j] << '\t'; cout << endl; }*/ } cin >> count; while (count--) { int a, b, c; cin >> a >> b; c = a * 10 + b; int ansr = 0, ansc = 0, e = 0; for (int i=0; i < r; i++) { for (int j = 0; j < c; j++) if (c == s[i][j]) { ansr = i; ansc = j; e = 1; } } if (e)cout << ansr + 1 << ansc + 1 << endl; else cout << "gone" << endl; } } void EX(int a, int b, int c, int d) { int m = s[a - 1][b - 1]; s[a - 1][b - 1] = s[c - 1][d - 1]; s[c - 1][d - 1] = m; } void copy(char type, int p, int q) { if (type == 'R') { for (int i = 0; i < c; i++) s[p][i] = s[q][i]; } else { for (int i = 0; i < r; i++) s[i][p] = s[i][q]; } } void DR(int n) { for (int i = n - 1; i < r-1; i++) copy('R', i, i + 1); for (int i = 0; i < c; i++) s[r - 1][i] = 0; r--; } void DC(int n) { for (int i = n - 1; i < c-1; i++) copy('C', i, i + 1); for (int i = 0; i < r; i++) s[i][c - 1] = 0; c--; } void IC(int n) { for (int i = r; i >= n; i--) copy('R', i, i - 1); for (int i = 0; i < c; i++) s[n - 1][i] = 0; r++; } void IR(int n) { for (int i = c; i >= n; i--) copy('C', i, i - 1); for (int i = 0; i < r; i++) s[i][n - 1] = 0; c++; }
debug很痛苦,发现几个平常疏忽的问题
1.char数组的长度要比储存的字符串长度至少加一,最后一位是‘\0';
2.operation是程序中定义的char字符串,但是发现用if(operation=="EX")
进行判断时出现问题,最终只能用单独比较字符的方法代替,可能需要strmp()函数,具体没试不太清楚
3.列表初始化问题,在对数组进行列表初始化为0时发生了一些状况,居然cout无法输出结果,最终用循环代替,还有待查证
4.忽视表达式的副作用,导致在考虑多个操作同时进行时定义了常数k,使用k++计算操作之间的影响,最终让k错误叠加,在使用++,--,cin输入时要小心
5.数组的标号从0开始,有时候出问题
书上的解答也贴在下面
#include<iostream>
#include<cstring>
const int maxd = 100;
const int BIG = 10000;
int r, c, n, d[maxd][maxd], d2[maxd][maxd], ans[maxd][maxd], cols[maxd];
void copy(char type, int p, int q);
void del(char type);
void ins(char type);
void copy(char type, int p, int q)
{
if (type == 'R')
{
for (int i = 1; i <= c; i++)
d[p][i] = d2[q][i];
}
else
{
for (int i = 1; i <= c; i++)
d[i][p] = d2[i][q];
}
}
void del(char type)
{
memcpy(d2, d, sizeof(d));
int cnt = type == 'R' ? r : c, cnt2 = 0;
for (int i = 1; i <= cnt; i++)
{
if (!cols[i])copy(type, ++cnt2, i);
if (type == 'R')r = cnt2; else c = cnt2;
}
}
void ins(char type)
{
memcpy(d2, d, sizeof(d));
int cnt = type == 'R' ? r : c, cnt2 = 0;
for (int i = 1; i <= cnt; i++)
{
if (cols[i])copy(type, ++cnt2, 0);
copy(type, ++cnt2, i);
}
if (type == 'R')r = cnt2; else c = cnt2;
}
int main()
{
using namespace std;
int r1, c1, r2, c2, q, kase = 0;
char cmd[10];
memset(d, 0, sizeof(d));
while (cin >> r >> c >> n&&r)
{
int r0 = r, c0 = c;
for (int i = 1; i <= r; i++)
for (int j = 1; j <= c; j++)
d[i][j] = i*BIG + j;
while (n--)
{
cin >> cmd;
if (cmd[0] == 'E')
{
cin >> c1 >> r1 >> c2 >> r2;
int t = d[r1][c1]; d[r1][c1] = d[r2][c2]; d[r2][c2] = t;//??
}
else
{
int a, x;
cin >> a;
memset(cols, 0, sizeof(cols));
for (int i = 0; i < a; i++)
{
cin >> x; cols[x] = 1;
}
if (cmd[0] == 'D')del(cmd[1]); else int(cmd[1]);
}
}
memset(ans, 0, sizeof(ans));
for (int i = 1; i <= r; i++)
for (int j = 1; j <= c; j++)
{
ans[d[i][j] / BIG][d[i][j] % BIG] = i*BIG + j;
}
if (kase > 0)cout << endl;
cout << "Spreadsheet #" << ++kase;
cin >> q;
while (q--)
{
cin >> r1 >> c1;
cout << "Cell data in (" << r1 << "," << c1 << ") ";
if (ans[r1][c1] == 0)cout << "GONE" << endl;
else cout << "move to (" << ans[r1][c1] / BIG << "," << ans[r1][c1] % BIG << ")\n";
}
}
}
书上的做法中更为简洁,首先是操作函数选择先拷贝再copy,更为直观,关键是在处理同时操作时定义数组cols来标记需要删除或添加的标号,然后用if语句来处理,简化很多,还有将DC DR合并为del函数,进一步简化问题,在判断指令时也更为方便。一个细节就是直接用数组标号对应表格标号,避免了数组从0开始标号的问题。另外,使用了memset,memcpy函数,进一步简化代码。
思路二,不生成表格,直接看每个原始cell的改变,代码如下
#include<iostream>
#include<cstring>
const int maxd = 100;
int simulate(int* r0, int* c0);
struct command {
char c[5];
int r1, c1, r2, c2;
int a, x[20];
}cmd[maxd];
int r, c, n;
int simulate(int* r0, int* c0)
{
for (int i = 0; i < n; i++)
{
if (cmd[i].c[0] == 'E')
{
if(cmd[i].r1==*r0&&cmd[i].c1==*c0)
{
*r0 = cmd[i].r2; *c0 = cmd[i].c2;
}
else if (cmd[i].r2 == *r0&&cmd[i].c2 == *c0)
{
*r0 = cmd[i].r1; *c0 = cmd[i].c1;
}
}
else
{
int dr = 0, dc = 0;
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++;
}
else
{
if (cmd[i].c[1] == 'R'&&x == *r0)return 0;
if (cmd[i].c[1] == 'C'&&x == *c0)return 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()
{
using namespace std;
int r0, c0, q, kase = 0;
while (cin >> r >> c >> n&&r)
{
for (int i = 0; i < n; i++)
{
cin >> cmd[i].c;
if (cmd[i].c[0] == 'E')
cin >> cmd[i].r1 >> cmd[i].c1 >> cmd[i].r2 >> cmd[i].c2;
else
{
cin >> cmd[i].a;
for (int j = 0; j < cmd[i].a; j++)
cin >> cmd[i].x[j];
}
}
if (kase > 0)cout << endl;
cout << "Spreadsheet #" << ++kase << endl;
cin >> q;
while (q--)
{
cin >> r0 >> c0;
cout << "Cell data in (" << r0 << "," << c0 << ") ";
if (!simulate(&r0, &c0))cout << "GONE\n";
else cout << "moved to (" << r0 << "," << c0 << ") ";
}
}
}
这样做则更为简单,要对每个变量进行相同操作,就必须把操作储存起来,就要用到数列,但是数列各个元素格式相同,就必然要用到结构。先把所有操作用结构数组储存然后编写simulate程序读取cmd数组的操作并执行。要求自定义函数修改main局部变量,用指针传递即可。