UVa 512 Spreadsheet Tracking

来源:互联网 发布:网络谣言的危害 案例 编辑:程序博客网 时间:2024/06/05 18:34

题目意思就是对电子表格进行一系列操作后追踪各cell的去向,基本操作类型有EX DR DC IR IC 5种,注意一个操作可能包含多个同时进行的子操作

sample input

7 95DR   2  1 5DC  4  3 6 7 9IC  1  3IR  2  2 4EX 1 2 6 544 85 57 86 50 0

sample output

Spreadsheet #1
Cell data in (4,8) moved to (4,6)Cell data in (5,5) GONECell 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局部变量,用指针传递即可。

原创粉丝点击