算法竞赛入门经典(第二版) | 例题4-5 追踪电子表格中的单元格 (UVa512,Spreadsheet Tracking,World Finals)(解法一)
大意
輸入:r(行)c(列)n(種操作)m(個行/列),給出具體行/列 x(個坐標),給出具體坐標。
輸出:m個坐標經過n種操作后分別移動到了哪里。
注意:所有操作都是根據原始表進行的,如:1,2,3行前插入空行,此123行指原表的123行,而不是插入一行后值變動。
輸入輸出格式:
1、輸入m和n其一得零時結束。每個輸出結果直接無空行。
2、每個輸出之前需要有空行,且最后一個輸出前沒空行。
分析:
核心難點在于如何在插入和刪除時,每次操作都是相對于原表進行的。
我的失敗思路:
1、若刪除多行/列,如何判斷刪除的是原始表中的行或列?
先將所在行全部置零,全遍歷完后,統一刪除為0的行。 注意判斷條件要用while,if檢測不到連續行為0的情況
注意邊界條件!!!!!!!若最后一行/列為0,直接自減,跳過循環, 否則會先入死循環
2、行和列的刪除解決了,如何判斷插入的是原始表中的行和列?
到這里我就卡住了,思考再三,覺得再繼續下去學到的東西也不多了, 于是開始理解劉先生的代碼。(后來仔細看題,其實是我漏掉了一個值,導致無法知道接下來要輸入多少數字,如果用數組的方式應該也可以做出來。)
劉先生的正確思路:
劉先生的刪除是將待刪的行、列存入數組, 給d賦值時,加一層篩選,若是數組里的行、列數,則取消賦值。
插入則是多插一層0,0。
傳送門→UVa-512
沒使用過該網站的同學請猛戳這里→vJudge教程
百度翻譯→百度翻譯
代碼:
#include<stdio.h> #include<string.h> #define maxd 100 #define 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) {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(scanf("%d%d%d", &r, &c, &n) == 3 && 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--) {scanf("%s", cmd);if(cmd[0] == 'E') {scanf("%d%d%d%d", &r1, &c1, &r2, &c2);int t = d[r1][c1]; d[r1][c1] = d[r2][c2]; d[r2][c2] = t;} else {int a, x;scanf("%d", &a);memset(cols, 0, sizeof(cols));for(int i = 0; i < a; i++) { scanf("%d", &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 > 0) printf("\n");printf("Spreadsheet #%d\n", ++kase);scanf("%d", &q);while(q--) {scanf("%d%d", &r1, &c1);printf("Cell data in (%d,%d) ", r1, c1);if(ans[r1][c1] == 0) printf("GONE\n");else printf("moved to (%d,%d)\n", ans[r1][c1]/BIG, ans[r1][c1]%BIG);}}return 0; }收獲:
1、鞏固了調試技巧(設置輸出函數更加靈活, 標紅函數頭部看的更加清楚)
2、自頂向下的創建方法。思路清晰。
3、函數復用 , 我雖然寫了函數,但還是有些臃腫了,只相當于將一部分代碼搬到外面去了。 沒有達到復用的效果
而劉先生是判斷刪除or插入,此為一級復用;接下來將判斷出的結果送入二級復用。
4、判斷回車是否被吸取干凈:cout << 1 << (char)getchar() << 1; //判斷回車是否被吸取干凈
5、插入、刪除皆可以0或其他代替,減少代碼量
6、a[i][j] = i*BIG + j;后, a[i][j]/BIG = i ; a[i][j]%BIG = j;好處是:若想對表插入或刪除,直接看數組中值是否等于cols中值。
7、每個輸出前有空行,但最后一個輸出前沒空行,采取“輸出前加空行的方法,且第一個輸出前無空行”的方法
8、同時刪除行、列:查表。
9、圖表等模式注意邊界值的運算。
最后,分享一條大牛的建議(對筆者受益匪淺):平時在做題的時候,一定要尋找最優解,而不是 ac 了就不管了,應該多看看別人的解法。
解法二傳送門→解法2
總結
以上是生活随笔為你收集整理的算法竞赛入门经典(第二版) | 例题4-5 追踪电子表格中的单元格 (UVa512,Spreadsheet Tracking,World Finals)(解法一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法竞赛入门经典(第二版) | 例题4-
- 下一篇: 算法竞赛入门经典(第二版) | 例题4-