第三章 数组和字符串(习题篇)
习题3-1:得分(Score,UVa1585)
给出一个由O和X组成的串(长度为1~80),统计得分。每个O的得分为目前连续出现的O的个数,X的得分为0。例如,OOXXOXXOOO的得分1+2+0+0+1+0+0+1+2+3。
分析 :输入字符串后从字符串开头循环,是‘X’就把O的权值改为0;是‘O’就权值加1,答案加上权值。最后输出答案。
#include <stdio.h>
#include<string.h>
#define maxn 10000
int main()
{
/*freopen("input.txt", "r", stdin);*/
char s[maxn];
scanf("%s", s);
int kase = 0;
int tran = 0;
for (int i = 0;i < strlen(s);i++)
{
if (kase)
printf("+");
else
kase = 1;
if (s[i] == 'O')
{
tran++;
}
else
{
tran = 0;
}
printf("%d", tran);
}
printf("\n");
return 0;
}
习题3-2:分子量(Molar Mass,UVa1586)
给出一种物质的分子式(不带括号),求分子量。本题中的分子式只包含4种原子,分别为C, H, O, N,原子量分别为12.01, 1.008, 16.00, 14.01(单位:g/mol),输入t个分子式,输出分子量,保留三位小数。
输入:
C
C6H5OH
NH2CH2COOH
C12H22O11
输出:
12.010
94.108
75.070
342.296
#include <stdio.h>
#include<ctype.h>
#define maxn 10000
int main()
{
/*freopen("input.txt", "r", stdin);*/
char s[maxn];
scanf("%s", s);
int i = 0;
double sum = 0;
double temp;
while (s[i])
{
switch (s[i])
{
case 'C':
temp = 12.01;
break;
case 'H':
temp = 1.008;
break;
case 'O':
temp = 16.00;
break;
case 'N':
temp = 14.01;
break;
}
int num = 0;
while (isdigit(s[i + 1]))
{
num = num * 10 + (s[++i] - '0');
}
if (!num)
{
num = 1;
}
temp = temp*num;
sum += temp;
i++;
}
printf("%.3lfg/mol\n", sum);
return 0;
}
习题3-3:数数字(Digit Counting,UVa1225)
把前n(n<=100000)个整数顺序写在一起,123456789…数一数0-9各出现多少次。
#include <stdio.h>
#include<string.h>
#define maxn 100001
int main()
{
/*freopen("input.txt", "r", stdin);*/
char s[maxn];
int count[10];
memset(count, 0, sizeof(count));
scanf("%s", s);
for (int i = 0;i < strlen(s);i++)
{
count[s[i] - '0']++;
}
for (int i = 0;i < 10;i++)
{
printf("%d ", count[i]);
}
printf("\n");
return 0;
}
习题3-4:周期串(Periodic Strings,UVa455)
如果一个字符串可以由某个长度为k的字符串重复多次得到,则称该串以k为周期。例如,abcabcabcabc以3为最小周期(注意,它也以6和12为周期)。输入一个长度不超过80的字符串,输出其最小周期。
答案一:
#include <stdio.h>
#include<string.h>
#define maxn 81
int main()
{
/*freopen("input.txt", "r", stdin);*/
char s[maxn];
scanf("%s", s);
int p = 0, q = 0, i = 0, j = 0;
int n = strlen(s);
for (i = 0;i < n;i++)
{
j = n % (i + 1);
if (j != 0)
{
continue;
}
j = n / (i + 1);
for (p = 0;p < j;p++)
{
for (q = 0;q <= i;q++)
{
if (s[q] != s[p*(i + 1) + q])
{
q = i + 1;//退出循环for (q = 0;q <= i;q++)
p = j + 1;//退出循环for (p = 0;p < j;p++)
}
}
}
if (p == j)
{
break;
}
}
i++;
printf("最小周期是:%d\n", i);
return 0;
}
答案二:
#include <stdio.h>
#include<string.h>
#define maxn 81
int main()
{
/*freopen("input.txt", "r", stdin);*/
char s[maxn];
scanf("%s", s);
int i = 0, j = 0;
int n = strlen(s);
for (i = 1;i <= n;i++)
{
j = n % i;
if (j != 0)
{
continue;
}
bool isBreak = false;
for (j = i;j < n;j++)
{
if (s[j] != s[j%i])
{
isBreak = true;
break;
}
}
if (!isBreak)
{
break;
}
}
printf("最小周期是:%d\n", i);
return 0;
}
习题3-5:谜题(Puzzle,UVa227)
有一个5*5的网格,其中恰好有一个格子是空的,其他格子各有一个字母,一共有四种指令:A,B,L,R,分别表示把空格上、下、左、右的相邻字母移到空格中。输入初始网格和指令序列(分别以数字0结束),输出指令执行完毕后的网格。如果有非法指令,应输出"This puzzle has no final configuration.",例如,图执行ARRBBL0。
题目分析:题目需要做的事情
①输入55的字符,每个格子有一个字母,有一个格子是空格
②找出输入字符空格的具体位置,保存下来
③之后分别检测指令A,B,L,R,这里还需要注意边界的地方,
④最后根据指令进行移动,最后从新输出每个格子的每个字符
#include <stdio.h>
#include <string.h>
#define maxn 100
int main()
{
/*freopen("input.txt", "r", stdin);*/
char cmd[maxn];
char s[5][5] = { 'T','R','G','S','J',
'X','D','O','K','I',
'M',' ','V','L','N',
'W','P','A','B','E',
'U','Q','H','C','F' };
int x, y;
for (int i = 0;i < 5;i++)
{
for (int j = 0;j < 5;j++)
{
if (s[i][j] == ' ')
{
x = i;
y = j;
}
printf("%2c", s[i][j]);
}
printf("\n");
}
while (scanf("%s", cmd) == 1)
{
int i = 0;
while (cmd[i] != '0')
{
if (cmd[i] == 'A'&&x != 0)
{
s[x][y] = s[x - 1][y];
s[--x][y] = ' ';
}
else if (cmd[i] == 'B'&&x != 4)
{
s[x][y] = s[x + 1][y];
s[++x][y] = ' ';
}
else if (cmd[i] == 'L'&&y != 0)
{
s[x][y] = s[x][y - 1];
s[x][--y] = ' ';
}
else if (cmd[i] == 'R'&&y != 4)
{
s[x][y] = s[x][y + 1];
s[x][++y] = ' ';
}
else
{
printf("This puzzle has no final configuration.\n");
cmd[i] = '0';
break;
}
i++;
}
printf("After %s\n", cmd);
for (int i = 0;i < 5;i++)
{
for (int j = 0;j < 5;j++)
{
printf("%2c", s[i][j]);
}
printf("\n");
}
}
return 0;
}
习题3-6:纵横字谜的答案(Crossword Answers,UVa232)
输入一个r行c列(1<=r,c<=10)的网格,黑格用‘’表示,每个白格都填有一个字母。如果一个白格的左边相邻位置或者上边相邻位置没有白格(可能是黑格,也可能出了网格边界),则称这个白格是一个起始格。首先把所有的起始格从上到下,从左到右的顺序编号为1,2,3…。
接下来要输出所由横向单词,这些单词必须从一个起始格开始,向右延伸到一个黑格的左边,或者整个网格的最右列。最后找出所有竖向单词。这些单词必须从一个起始格开始,向下延伸到一个黑格的上边或者整个网格的最下行。
样例输入:
2 2
AT
O
6 7
AIMDEN
MEONE
UPONTO
SOERIN
SAOR
IES*DEA
0
样例输出:
puzzle #1:
Across
1.AT
3.O
Down
1.A
2.TO
puzzle #2:
Across
1.AIM
4.DEN
7.ME
8.ONE
9.UPON
11.TO
12.SO
13.ERIN
15.SA
17.OR
18.IES
19.DEA
Down
1.A
2.IMPOSE
3.MEO
4.DO
5.ENTIRE
6.NEON
9.US
10.NE
14.ROD
16.AS
18.I
20.A
思路一:
1.横向的时候每行扫描数组;
2.找到起始格并计数,输出每个字母,碰到和边界则输出换行;
3.纵向的时候也是每行扫描数组;
4.找到起始格并计数,向下输出单词并把输出过的字母赋值为0,直到碰到和边界输出换行;
5.赋值为0的起始格不需要向下输出单词。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define maxn 1000
int main()
{
freopen("input.txt", "r", stdin);
int r, c;
char line[maxn];
int num = 0;
while (scanf("%d", &r) == 1 && r >= 1 && scanf("%d", &c) == 1)
{
printf("\npuzzke #%d\n", ++num);
char * ch1 = (char*)malloc(r*c*sizeof(char));
for (int i = 0;i < r;i++)
{
scanf("%s", line);
for (int j = 0;j < c;j++)
{
*(ch1 + i*c + j) = line[j];
}
}
int count = 0;
printf("Across:\n");
for (int i = 0;i < r;i++)
{
for (int j = 0;j < c;j++)
{
if ((*(ch1 + i*c + j) != '*') && (j == 0 || *(ch1 + i*c + j - 1) == '*' || i == 0 || *(ch1 + (i - 1)*c + j) == '*'))
{
count++;
printf(" %d.%c", count, *(ch1 + i*c + j));
j++;
while (j < c&&*(ch1 + i*c + j) != '*')
{
if (i == 0 || *(ch1 + (i - 1)*c + j) == '*')
{
count++;
}
printf("%c", *(ch1 + i*c + j));
j++;
}
printf("\n");
}
}
}
count = 0;
printf("Down:\n");
for (int i = 0;i < r;i++)
{
for (int j = 0;j < c;j++)
{
if ((*(ch1 + i*c + j) != '*') && (j == 0 || *(ch1 + i*c + j - 1) == '*' || i == 0 || *(ch1 + (i - 1)*c + j) == '*'))
{
count++;
if (*(ch1 + i*c + j) == '0')
{
continue;
}
printf(" %d.%c", count, *(ch1 + i*c + j));
int y = i + 1;
while (y < r && (*(ch1 + y*c + j) != '*'))
{
printf("%c", *(ch1 + y*c + j));
*(ch1 + y*c + j) = '0';
y++;
}
printf("\n");
}
}
}
free(ch1);
}
return 0;
}
思路二:
1.横向的时候每行扫描数组;
2.分辨出起始格、号格和不是起始格的白格;
3.是号格不做处理继续循环查找;
4.是起始格的话就计数,进一步判断是否是一个单词的开头还是单词开头字母后的字母;
5.是不是起始格的白格直接输出字母;
6.纵向的时候也是每行扫描数组;
7.分辨出号格和起始格;
8.是号格不做处理继续循环查找;
9.是起始格计数并判断是否是一个单词的开头,是开头字母则往后输出单词。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define maxn 1000
int main()
{
freopen("input.txt", "r", stdin);
int r, c;
char line[maxn];
int num = 0;
while (scanf("%d", &r) == 1 && r >= 1 && scanf("%d", &c) == 1)
{
printf("\npuzzke #%d\n", ++num);
char * ch1 = (char*)malloc(r*c*sizeof(char));
for (int i = 0;i < r;i++)
{
scanf("%s", line);
for (int j = 0;j < c;j++)
{
*(ch1 + i*c + j) = line[j];
}
}
int count = 0;
printf("Across:");
for (int i = 0;i < r;i++)
{
for (int j = 0;j < c;j++)
{
if (*(ch1 + i*c + j) == '*')
continue;
if (j == 0 || *(ch1 + i*c + j - 1) == '*' || i == 0 || *(ch1 + (i - 1)*c + j) == '*')
{
count++;
if (j == 0 || *(ch1 + i*c + j - 1) == '*')
{
printf("\n %d.%c", count, *(ch1 + i*c + j));
}
else
{
printf("%c", *(ch1 + i*c + j));
}
}
else
{
printf("%c", *(ch1 + i*c + j));
}
}
}
count = 0;
printf("\nDown:");
for (int i = 0;i < r;i++)
{
for (int j = 0;j < c;j++)
{
if (*(ch1 + i*c + j) == '*')
continue;
if (j == 0 || *(ch1 + i*c + j - 1) == '*' || i == 0 || *(ch1 + (i - 1)*c + j) == '*')
{
count++;
if (i == 0 || *(ch1 + (i - 1)*c + j) == '*')
{
printf("\n %d.%c", count, *(ch1 + i*c + j));
int y = i + 1;
while (y < r && (*(ch1 + y*c + j) != '*'))
{
printf("%c", *(ch1 + y*c + j));
y++;
}
}
}
}
}
printf("\n");
free(ch1);
}
return 0;
}
习题3-7:DNA序列(DNA Consensus String,UVa1368)
给定m个长度为n的DNA序列,求一个DNA序列,使其到所有这些序列的总hamming距离尽量小,如果有多个解,输出字典顺序的最小解。(hamming距离是两个序列不同字符的个数)。
输入:
5 8
TATGATAC
TAAGCTAC
AAAGATCC
TGAGATAC
TAAGATGT
输出:
TAAGATAC
思路:用数组统计各列各类字符的个数,然后取每一列出现次数最多的字符,拼接成即可,如果次数相同则ASCI码小的优先。
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxn 1000
char line[maxn];
int main()
{
freopen("input.txt", "r", stdin);
int m, n;
scanf("%d%d", &m, &n);
char *s = (char *)malloc(m*n*sizeof(char));
char *mark = "ACGT";
int ans[4];
int max, index;
memset(ans, 0, sizeof(ans));
for (int i = 0;i < m;i++)
{
scanf("%s", line);
for (int j = 0;j < n;j++)
{
*(s + i*n + j) = line[j];
}
}
for (int i = 0;i < n;i++)
{
memset(ans, 0, sizeof(ans));
for (int j = 0;j < m;j++)
{
if (*(s + j*n + i) == 'A')
{
ans[0]++;
}
if (*(s + j*n + i) == 'C')
{
ans[1]++;
}
if (*(s + j*n + i) == 'G')
{
ans[2]++;
}
if (*(s + j*n + i) == 'T')
{
ans[3]++;
}
}
max = ans[0];
index = 0;
for (int z = 1;z < 4;z++)
{
if (max <= ans[z])
{
if (max == ans[z])
{
if (mark[z] - mark[max] > 0)
continue;
}
max = ans[z];
index = z;
}
}
printf("%c", mark[index]);
}
printf("\n");
free(s);
return 0;
}
习题3-8:循环小数(Repeating Decimals,UVa202)
输入整数a和b(0<=a<=3000,1<=b<=3000),输出a/b的循环小数表示以及其循环节长度。例如 a=5 b=43 小数表示为0.(116279069767441860465),循环节长度为21。
思路:模拟长除法的计算过程。
①mod = a%b;
②小数 = (mod10) / b;
③mod = (mod10)%b;
循环②③步,当出现重复的余数的时候,也就是循环节出现了。如果是无理数的时候在0~b-1个小数后必会出现循环(出现相同的余数)。
#include <stdio.h>
#include<string.h>
#define maxn 3000
bool line[maxn];
int main()
{
/*freopen("input.txt", "r", stdin);*/
int a, b;
scanf("%d%d", &a, &b);
memset(line, 0,sizeof(line));
int count = 0;
int mod;
mod = a%b;
printf("%d", a / b);
if (mod == 0)
{
printf("\n");
}
else
{
printf(".(");
while (mod && !line[mod])
{
count++;
line[mod] = true;
a = (mod * 10) / b;
mod = (mod * 10) % b;
printf("%d", a);
}
printf(") %d\n", count);
}
return 0;
}
输入:
5 43
输出:
0.(116279069767441860465) 21
习题3-9:子序列(All in All,UVa10340)
输入s和t两个字符串,t通过删除0个或一些字符能够得到s。
思路:从t的左边遍历到右边,找到s的第一个字母后,继续往后找到s的第二个字母,如果能找到s中的全部字母,则t通过删除0个或一些字符能够得到s。
#include <stdio.h>
#include<string.h>
#define maxn 1000
int main()
{
/*freopen("input.txt", "r", stdin);*/
char s[maxn];
char t[maxn];//从t中剔除
printf("Put in a string:\n");
scanf("%s", t);
printf("Put in a substring:\n");
scanf("%s", s);
int len_t, len_s;
int i, j;
len_t = strlen(t);
len_s = strlen(s);
for (i = 0, j = 0;(j < len_s) /*&& (i < len_t)*/ && (len_s - j) <= (len_t - i);i++)
{
if (t[i] == s[j])
j++;
}
if (j == len_s)
{
printf("Find!\n");
}
else
{
printf("No find!\n");
}
return 0;
}
习题3-10:盒子(Box,UVa1587)
给定6个矩形的长和宽wi和hi(1≤wi,hi≤1000),判断它们能否构成长方体的6个面。
思路一:
1.使用一个2维数组,找到两个相同的面并将其排在一起,找不到两个相同的面就不能构成长方形;
2.第一个面的一条边在第二个面有一条相同的边,第一个面的另一个边在三个边有条相同的边,第二个面和第三个面剩下的边也相同。
#include <stdio.h>
int main()
{
freopen("input.txt", "r", stdin);
int a[6][2];
int temp;
bool flag;
for (int i = 0;i < 6;i++)
{
scanf("%d", &a[i][0]);
scanf("%d", &a[i][1]);
}
for (int i = 0;i < 6;i+=2)
{
flag = false;
for (int j = i + 1;j < 6;j++)
{
if (a[i][0] == a[j][0] && a[i][1] == a[j][1])
{
temp = a[i + 1][0];
a[i + 1][0] = a[j][0];
a[j][0] = temp;
temp = a[i + 1][1];
a[i + 1][1] = a[j][1];
a[j][1] = temp;
flag = true;
break;
}
else if (a[i][0] == a[j][1] && a[i][1] == a[j][0])
{
temp = a[i + 1][0];
a[i + 1][0] = a[j][1];
a[j][1] = temp;
temp = a[i + 1][1];
a[i + 1][1] = a[j][0];
a[j][0] = temp;
flag = true;
break;
}
}
if (!flag)
{
printf("Impossible!\n");
return 0;
}
}
if (a[0][0] == a[2][0])
{
if (a[0][1] == a[4][0] && a[2][1] == a[4][1])
{
printf("Possible!\n");
}
else if (a[0][1] == a[4][1] && a[2][1] == a[4][0])
{
printf("Possible!\n");
}
else
{
printf("Impossible!\n");
}
}
else if (a[0][0] == a[2][1])
{
if (a[0][1] == a[4][0] && a[2][0] == a[4][1])
{
printf("Possible!\n");
}
else if (a[0][1] == a[4][1] && a[2][0] == a[4][0])
{
printf("Possible!\n");
}
else
{
printf("Impossible!\n");
}
}
else if (a[0][0] == a[4][0])
{
if (a[0][1] == a[2][0] && a[2][1] == a[4][1])
{
printf("Possible!\n");
}
else if (a[0][1] == a[2][1] && a[2][0] == a[4][1])
{
printf("Possible!\n");
}
else
{
printf("Impossible!\n");
}
}
else if (a[0][0] == a[4][1])
{
if (a[0][1] == a[2][0] && a[2][1] == a[4][0])
{
printf("Possible!\n");
}
else if (a[0][1] == a[2][1] && a[2][0] == a[4][0])
{
printf("Possible!\n");
}
else
{
printf("Impossible!\n");
}
}
else
{
printf("Impossible!\n");
}
return 0;
}
思路二:先是在输入数据的时候就先对其作出处理,保证x<y; 再是对存储在结构体中的数据排序。 如果x相同,则按照y的值从小到大排序;否则按照x的值从小到大排序。
?????