UVA

来源:互联网 发布:淘宝新店流量扶持 编辑:程序博客网 时间:2024/06/05 06:48
//法1:先模拟操作,算出最后的电子表格,接着在每次查询时直接在电子表格中,找到所求的单元格/*  此方法最关键的地方,应是怎样建立原来的位置和后来的位置的联系    入门经典的法一,很巧妙地借助了这样的数组定义;  d[i][j] = i*BIG + j,记录下了原来的位置...在后面的插入、删除和交换等等步骤之后  虽然d[i][j]里装的数字可能变化了,可是只要计算 d[i][j] / BIG, d[i][j] % BIG,得到的就是这个位置的初始位置的行数和列数了    以及,填充ans数组时,相当于遍历每个位置,每个位置(i,j)会有一个对应的数字 i * BIG +j,我们可以找到它原来的行列位置,作为ans[i][j]中的i,j(怎么找呢,当然是用d数组里的值整除BIG和取模BIG啦~),因此有 ans[d[i][j] / BIG][d[i][j] % BIG] = i * BIG + j;    它的含义是:原来第i行第j列的数字,现在放到了新的位置,而我如果想知道这个新的位置,只要将 (i * BIG + j) 整除BIG和取模BIG即可    所以,如果填充ans数组时,遇到了原来存在但现在被删掉了的数字,那么原来的行数和列数,一定不会作为ans[i][j]中的i和j,因为既然删除,最初的那个d[i][j]肯定也就被删掉了    如果填充ans数组时,遇到了新加上的数,那么它之前肯定没被填充到d数组,而全局数组d,没被填充的部分就是0,所以,它根本不会影响ans数组的正常填充    总之,这题很巧妙地借助了取模和整除,建立了原来的位置和现在的位置之间的关系,以及表示位置的 i*BIG + j,入门经典中指定的BIG是10000,但其实100就够了,它的目的只是让i被分离出来时,一定不会受到j进位的影响,既然i,j都是最大50,也就是最多2位,BIG用100也就够了    BTW,这题和 HDU - 6098 Inversion 其实有些异曲同工之妙,虽然看上去很不同,但它们都有一个共同点,都要和最初的标号(或是位置)建立上联系,对这题的这种方法,是利用乘法+加法、除法+取模,来将原来的位置和现在的位置建立联系(它们之间有个不会变化的纽带,就是构造出的那个数字,d[i][j] / BIG, d[i][j] % BIG,于是这就保证了,对于某个位置而言,只要它没被删除,无论它移动到那里,在别的位置上,仍然可以通过构造出的那个数字,整除和取模得到原先的位置)    这种思路实在是精妙,让人想对刘汝佳前辈伏地膜...    而hdu那题,是通过构造结构体,将序号和数值绑定起来  (没记错的话,这道题我已经在我的blog上发了题解啦,需要的不妨看看)    两题的共性就是:都要用一些特定方法或思路,来保证一个不变量,作为最初和最终状态的纽带  */


#include <iostream>#include <cstring>using namespace std;const int maxd = 100;const int BIG = 100;int r, c, n, d[maxd][maxd], d2[maxd][maxd], ans[maxd][maxd], cols[maxd];/*依次表示:行、列、操作次数d:将d中的值按照最初位置构造 i * BIG + j并赋值,d中的值会改变位置,但通过值仍能推出初始位置(除非删除)d2:起临时变量作用的数组,方便进行系列操作ans:下标对应初始位置,值对应最终位置的构造值 i * BIG + j,整除取模可得最终位置cols:表示每次插入或删除操作波及的行数或列数,因而每次操作前需清空*/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 <= r; 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(){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 >> r1 >> c1 >> r2 >> c2;swap(d[r1][c1], d[r2][c2]);}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 ins(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) cout << endl;cout << "Spreadsheet #" << ++kase << endl;cin >> q;while (q--){cin >> r1 >> c1;cout << "Cell data in (" << r1 << "," << c1 << ") ";if (ans[r1][c1] == 0) cout << "GONE" << endl;else cout << "moved to (" << ans[r1][c1] / BIG << "," << ans[r1][c1] % BIG << ")" << endl;}}return 0;}

//法二:先将所有的操作保存,然后对于每个查询重新执行每个操作,但不需要计算整个电子表格的变化,而只关注所查询的单元格的位置变化。对于题目给定的规模来说,这个方法不仅更好写,而且效率更高//入门经典的法二,代码就比较容易理解了,逻辑十分清楚

#include <iostream>#include <cstring>using namespace std;typedef pair<int, int> p;const int maxd = 10000;struct Command{char c[5];p pos1, pos2; //position 1, position 2int 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'){p pos3(r0, c0);if (cmd[i].pos1 == pos3){r0 = cmd[i].pos2.first;c0 = cmd[i].pos2.second;}else if (cmd[i].pos2 == pos3){r0 = cmd[i].pos1.first;c0 = cmd[i].pos1.second;}}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++;else if (cmd[i].c[1] == 'C' && x <= c0) dc++;}else{if (cmd[i].c[1] == 'R') {if (x == r0) return 0;if (x < r0) dr--;}else{if (x == c0) return 0;if (x < c0) dc--;}}}r0 += dr; c0 += dc;}}return 1;}int main(){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].pos1.first >> cmd[i].pos1.second >>  cmd[i].pos2.first >> cmd[i].pos2.second;else{cin >> cmd[i].a;for (int j = 0; j < cmd[i].a; j++)cin >> cmd[i].x[j];}}if (kase) 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" << endl;else cout << "moved to (" << r0 << "," << c0 << ")" << endl;}}return 0;}


原创粉丝点击