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;
}
常量表简化代码让我想起了以前杭电的一个水题
hdoj2005 第几天?
#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;
}
一般用fgets()可以搞定的,getchar()也可以。下面试试getchar()
经常看到有人用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