http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=96
uva401
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=96&page=show_problem&problem=342
这个题得了几次RE,千思万想把char *p都初始为NULL了(感觉没啥影响),然后发现主函数没有return 0; 加了上述效果提交AC了,然后去掉return 0;提交再次RE;
【注意】主函数一定要返回0!
题目不难,首先写好主函数,因为镜像回文一定属于回文,所以先判断是否是回文,不是回文又包括了镜像文和 不是镜像文也不是回文(输出为不是回文)
因此主函数写完,剩下的工作就是写几个谓词函数了
find函数:本来是想直接用strchr()的,没想到这个函数返回的是第一次查到到位置,而且这个位置并不是数组的下标,因此效果和find很不一样
看到strchr()比较适合作为查找一个字符是否存在于指定字符串,返回值不是很有用
有一个小细节感觉比较经常遇到——
while (*r != '\0') { if (*l != *r) break; l--; r++; }这个为什么不写成*l-- != *r++,因为一旦发现不等,r--和r++还是执行了,如果后面你 用到*r == '\0'来区分是通过break跳出while还是通过(*r == '\0')跳出while就不妙了。
好在,这里我换了一种写法,直接通过return直接跳出,这样是写成*l-- != *r++的;
#include <stdio.h> #include <string.h> #define N 300 char *selfmirrorch = "AHIMOTUVWXY18"; char real[N] = "AEHIJLMOSXTUVWYZ12358\0"; char mirr[N] = "A3HILJMO2XTUVWY51SEZ8\0"; char str[N]; int find(char *s, char ch) { char *p = s; for (; *p != '\0'; p++) { if (*p == ch) return p-s; } return -1; } int isre_palin(char *s) { char *l = NULL, *r = NULL; char *tmp = s + strlen(s)/2; l = tmp-1; r = 0 == strlen(s)%2 ? tmp : tmp+1; while (*r != '\0') { if (*l-- != *r++) return 0; } return 1; } int isbelong_selfmirrorch(char *s) { char *p = s; for (; *p != '\0'; p++) { if (strchr(selfmirrorch, *p) == NULL) return 0; } return 1; } int ismi(char *s) { char *l = NULL, *r = NULL; char *tmp = s + strlen(s)/2; l = tmp-1; r = 0 == strlen(s)%2 ? tmp : tmp+1; while (*r != '\0') { if (find(real, *l) == -1 || find(mirr, *r) == -1) return 0; if (find(real, *l--) != find(mirr, *r++)) return 0; } return 1; } int main(void) { while (scanf("%s", str) != EOF) { if (isre_palin(str)) { if (isbelong_selfmirrorch(str)) { printf("%s -- is a mirrored palindrome.\n\n", str); } else { printf("%s -- is a regular palindrome.\n\n", str); } } else if (ismi(str)) { printf("%s -- is a mirrored string.\n\n", str); } else { printf("%s -- is not a palindrome.\n\n", str); } } return 0; }
uva10010
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=96&page=show_problem&problem=951
水题但是做了WA了几次,发现又是忽略掉了每组测试数据的输出数据之间要空一行,空行后AC。
思路:按题意从左上角到右下角开始遍历二维数组,首字母相同就停下来,对八个方向,逐一地 先检查边界条件,若不越界就赋值字符到tmp并封装为字符串,然后用strcmp()作比较,匹配即上面输出结果。
#include <stdio.h> #include <string.h> #define N 100 char map[N][N]; char str[N]; char tmp[N]; int save_i, save_j; int pos(int n, int m) { int i, j, k, l, x; for (i = 0; i != n; i++) { for (j = 0; j != m; j++) { if (map[i][j] == str[0]) { int jleft = j+1-strlen(str); int iup = i+1-strlen(str); int jright = j+strlen(str); int idown = i+strlen(str); x = 0; if (jleft >= 0) { for (l = j; l != j-strlen(str); l--) { tmp[x++] = map[i][l]; } tmp[x] = '\0'; if (strcmp(str, tmp) == 0) { save_i = i; save_j = j; return 1; } } x = 0; if (iup >= 0 && jleft >= 0) { for (k = i, l = j; k != i-strlen(str); k--, l--) { tmp[x++] = map[k][l]; } tmp[x] = '\0'; if (strcmp(str, tmp) == 0) { save_i = i; save_j = j; return 1; } } x = 0; if (iup >= 0) { for (k = i; k != i-strlen(str); k--) { tmp[x++] = map[k][j]; } tmp[x] = '\0'; if (strcmp(str, tmp) == 0) { save_i = i; save_j = j; return 1; } } x = 0; if (iup >= 0 && jright <= m) { for (k = i, l = j; l != j+strlen(str); k--, l++) { tmp[x++] = map[k][l]; } tmp[x] = '\0'; if (strcmp(str, tmp) == 0) { save_i = i; save_j = j; return 1; } } x = 0; if (jright <= m) { for (l = j; l != j+strlen(str); l++) { tmp[x++] = map[i][l]; } tmp[x] = '\0'; if (strcmp(str, tmp) == 0) { save_i = i; save_j = j; return 1; } } x = 0; if (idown <= n && jright <= m) { for (k = i, l = j; l != j+strlen(str); k++, l++) { tmp[x++] = map[k][l]; } tmp[x] = '\0'; if (strcmp(str, tmp) == 0) { save_i = i; save_j = j; return 1; } } x = 0; if (idown <= n) { for (k = i; k != i+strlen(str); k++) { tmp[x++] = map[k][j]; } tmp[x] = '\0'; if (strcmp(str, tmp) == 0) { save_i = i; save_j = j; return 1; } } x = 0; if (idown <= n && jleft >= 0) { for (k = i, l = j; k != i+strlen(str); k++, l--){ tmp[x++] = map[k][l]; } tmp[x] = '\0'; if (strcmp(str, tmp) == 0) { save_i = i; save_j = j; return 1; } } } } } } int main(void) { int tc; int n, m, i, j; int num; scanf("%d", &tc); while (tc--) { scanf("%d %d", &n, &m); for (i = 0; i != n; i++) { scanf("%s", str); for (j = 0; j != m; j++) map[i][j] = isupper(str[j]) ? tolower(str[j]) : str[j]; } scanf("%d", &num); for (j = 0; j != num; j++) { scanf("%s", str); for (i = 0; i != strlen(str); i++) { if (isupper(str[i])) str[i] = tolower(str[i]); } if (1 == pos(n, m)) printf("%d %d\n", save_i+1, save_j+1); } if (tc != 0) printf("\n"); } return 0; }
因为代码很长而且还经过了调试,一次性写对比较困难!因此去参看了其他人的代码。
得到一种很好的解法:
1、给字符矩阵留一个空白外围!(全局变量默认初始为0,即'\0'),这样就不用检查边界了!
2、八个方向逐一作检查,根据每个方向数组下标的变化规律(常量表)来简化代码,一代码变短,二代码不易错,可读性强!
因为不作边界检查,效率反而更好了。第一份代码是0.012s,这份是0.008s!
#include <stdio.h> #include <string.h> #define N 60 #define T 8 char map[N][N]; char str[N]; int posi, posj; typedef struct point { int x; int y; }point; point go[] = { {-1, -1}, {-1, +0}, {-1, +1}, {+0, -1}, {+0, +1}, {+1, -1}, {+1, +0}, {+1, +1} }; int pos(int n, int m) { int i, j, k, s; for (i = 1; i != n+1; i++) for (j = 1; j != m+1; j++) { if (map[i][j] == str[0]) { for (k = 0; k != T; k++) { for (s = 0; s != strlen(str); s++) { if (str[s] != map[i + s*(go[k].x)][j + s*(go[k].y)]) break; } if (s == strlen(str)) { posi = i; posj = j; return 1; } } } } } int main(void) { int tc; int n, m, i, j; int num; scanf("%d", &tc); while (tc--) { scanf("%d %d", &n, &m); for (i = 1; i != n+1; i++) { scanf("%s", str); for (j = 1; j != m+1; j++) map[i][j] = tolower(str[j-1]); } scanf("%d", &num); for (i = 0; i != num; i++) { scanf("%s", str); for (j = 0; j != strlen(str); j++) str[j] = tolower(str[j]); if (1 == pos(n, m)) printf("%d %d\n", posi, posj); } printf("%s", tc != 0 ? "\n" : ""); } return 0; }
#include <stdio.h> int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; int main(void) { int y, m, d; int i, ans; while (scanf("%d/%d/%d", &y, &m, &d) != EOF) { for (ans = d, i = 1; i != m; ans += days[i++]) ; printf("%d\n", ( m >= 3 && (0==y%400 || (0==y%4 && y%100!=0)) )? ans+1 : ans); } return 0; }
uva10361
WA了两次,原因里题意没理解明白,其实题目说的很清楚,句子的格式就是s1<s2>s3<s4>s5。而我却在考虑空格的问题。。。
最后直接看成上述形式,把s2 s3 s4 s5保存起来就搞定了。。。
#include <stdio.h> #include <string.h> #define N 110 char fir[N]; char sec[N]; char one[N], two[N], three[N], four[N]; int main(void) { int tc; char *p, *q; int i; scanf("%d%*c", &tc); while (tc--) { fgets(fir, sizeof (fir), stdin); fgets(sec, sizeof (sec), stdin); memset(one, 0, sizeof (one)); memset(two, 0, sizeof (two)); memset(three, 0, sizeof (three)); memset(four, 0, sizeof (four)); for (p = fir; *p != '<'; p++) ; for (i=0, p++; *p != '>'; p++) one[i++] = *p; one[i]='\0'; for (i=0, p++; *p != '<'; p++) two[i++] = *p; two[i]='\0'; for (i=0, p++; *p != '>'; p++) three[i++] = *p; three[i]='\0'; for (i=0, p++; *p != '\n'; p++) four[i++] = *p; four[i]='\0'; for (p = fir; *p != '\n'; p++) { if (*p != '<' && *p != '>') printf("%c", *p); } printf("\n"); for (q = sec; *q != '.'; q++) printf("%c", *q); printf("%s%s%s%s\n", three, two, one, four); } return 0; }
经常看到有人用getline(),参考别人的开源代码用getline()写了一份
#include <iostream> #include <cstdio> using namespace std; string s, s1, s2, s3, s4, s5; int main() { int tc; cin >> tc; getchar(); while (tc--) { getline(cin, s1, '<'); getline(cin, s2, '>'); getline(cin, s3, '<'); getline(cin, s4, '>'); getline(cin, s5, '\n'); getline(cin, s, '\n'); cout << s1 << s2 << s3 << s4 << s5 << endl; s.erase(s.end()-3, s.end()); //erase the last three character cout << s << s4 << s3 << s2 << s5 << endl; } return 0; }
uva537
题目比较水,按给出来的假定,只需找到两个等号的位置,读取信息即可。
但要写得简短,就要用好常量表和函数,比如sscanf()。
#include <stdio.h> #include <string.h> #define M 3 #define N 1000 char ch[] = "PUI"; char pref[] = "mkM"; char unit[] = "WVA"; double rate[M] = {0.001, 1000.00, 1000000.00}; double v[M]; char mark[M], line[N], prefch; int main(void) { int tc, k, i, j; char *p; scanf("%d%*c", &tc); for (k = 0; k != tc; k++) { memset(mark, 0, sizeof (mark)); fgets(line, sizeof (line), stdin); for (p = line; *p != '\n'; p++) if (*p == '=') { for (i = 0; ch[i] != *(p-1); i++) ; mark[i] = 1; sscanf(p+1, "%lf%c", &v[i], &prefch); for (j = 0; j != M; j++) if (pref[j] == prefch) v[i] *= rate[j]; } for (i = 0; mark[i] != 0; i++) ; if (0 == i) v[0] = v[1]*v[2]; /* P = U*I */ else if (1 == i) v[1] = v[0]/v[2]; /* U = P/I */ else v[2] = v[0]/v[1]; /* I = P/U */ printf("Problem #%d\n%c=%.2f%c\n\n", k+1, ch[i], v[i], unit[i]); } return 0; }
uva10115
采用一般方法,用三位数组存规则,然后把读入的行封装成字符串,最后进行更新(利用字符串处理函数strstr()和strcpy())
strcpy()有溢出的危险,下面改成strncpy()
#include <stdio.h> #include <string.h> #define N 100 char rules[N/10][2][N]; char str[N*3]; char tmp[N*3]; void update(char *d, char *s, char *r) { char *p; while ( (p = strstr(d, s)) != NULL ) { strcpy(tmp, p+strlen(s)); strcpy(p, r); strcpy(p+strlen(r), tmp); } } int main(void) { int n, i; while (scanf("%d%*c", &n) != EOF && n) { for (i = 0; i != n; i++) { fgets(rules[i][0], sizeof (rules[i][0]), stdin); rules[i][0][strlen(rules[i][0])-1] = '\0'; fgets(rules[i][1], sizeof (rules[i][1]), stdin); rules[i][1][strlen(rules[i][1])-1] = '\0'; } fgets(str, sizeof (str), stdin); str[strlen(str)-1] = '\0'; for (i = 0; i != n; i++) update(str, rules[i][0], rules[i][1]); printf("%s\n", str); } }
核心代码只有三行:
strcpy(tmp, p+strlen(s)); strcpy(p, r); strcpy(p+strlen(r), tmp);
【小结】
1、判断是否存在往往是一次遍历,如果在主函数中,往往要用到break;此时需注意自增条件的位置,否则可能导致无法判断出口;
推荐使用一个存在函数,这样可以用return语句,快速明朗!
2、审题方面:一定要先构造好主函数符合题意的输出规范!可以用文件读写的形式来快速测试!
3、程序绝不允许用“笨方法”!(当然过分追求精致不利于实现)
笨方法常常就是很多if else,本来是可以用for循环的却不会用!所以LRJ提出的学习目标包括【学会用常量表简化代码】
比如最简单的例子就是输出年月日求该日是该年的第几天?
4、如果不想用<cstdio>使用scanf()和cin混编,可以在主函数加入std::ios::sync_with_stdio (false);
处理字符串的函数介绍:
http://zhwen.org/tools/clib/string/bcmp.html