3.3 竞赛题目选讲

版权声明:转自翠羽黄衫的博客! https://blog.csdn.net/ac1085589289/article/details/86658728

例题3-1 TeX中的引号(Tex Quotes, UVa 272)

在TeX中,左双引号是“``”,右双引号是“’’”。输入一篇包含双引号的文章,你的任务是 把它转换成TeX的格式。
样例输入:
“To be or not to be,” quoth the Bard, “that
is the question”.
样例输出:
``To be or not to be,’’ quoth the Bard, ``that
is the question’’.

编程提示

  1. 本题的关键是,如何判断一个双引号是左双引号还是右双引号。方法很简单:使用一个标志变量即可。
  2. 使用fgetc(fin)可以从打开的文件fin中读取一个字符。一般情况下应当在检 查它不是EOF后再将其转换成char值。从标准输入读取一个字符可以用getchar,它等价于 fgetc(stdin)。
  3. "fgets(buf, maxn, fin)"将读取完整的一行放在字符数组buf中。应当保证 buf足够存放下文件的一行内容。除了在文件结束前没有遇到“\n”这种特殊情况外,buf总是 以“\n”结尾。当一个字符都没有读到时,fgets返回NULL。

程序3-5 TeX中的引号

#include<stdio.h> 
int main() 
{   
	int c, q = 1;  
	while((c = getchar()) != EOF) 
	{    
		if(c == '"') 
		{ 
			printf("%s", q ? "``" : "''"); 
			q = !q; 
		}    
		else printf("%c", c);  
	}  
return 0; 
}

例题3-2 WERTYU(WERTYU, UVa10082)

把手放在键盘上时,稍不注意就会往右错一 位。这样,输入Q会变成输入W,输入J会变成输 入K等。
输入一个错位后敲出的字符串(所有字母均 大写),输出打字员本来想打出的句子。输入保 证合法,即一定是错位之后的字符串。例如输入中不会出现大写字母A。
样例输入:
O S, GOMR YPFSU/
样例输出:
I AM FINE TODAY.

编程提示

  1. ,每输入一个字符,都可以直接输出一个字符,因此getchar是输入的理 想方法。
  2. :善用常量数组往往能简化代码。定义常量数组时无须指明大小,编译器会 计算。
  3. :如何进行这样输入输出变换呢?一种方法是使用if语句或者switch语 句,如"if(c == ‘W’) putchar(‘Q’)"。但很明显,这样做太麻烦。一个较好的方法是使用常量数 组,下面是完整程序:

程序3-6 WERTYU

#include<stdio.h> 
char s[] = "`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./"; //其实我一直不太明白这里为什么会有两个\\.
int main() 
{  
	int i, c;  
	while((c = getchar()) != EOF) 
	{    
		for (i=1; s[i] && s[i]!=c; i++); //找错位之后的字符在常量表中的位置
		if (s[i]) putchar(s[i-1]); //如果找到,则输出它的前一个字符    
		else putchar(c);  
	}  
return 0; 
}

例题3-3 回文词(Palindromes, UVa401)

输入一个字符串,判断它是否为回文串以及镜像串。输入字符串保证不含数字0。所谓 回文串,就是反转以后和原串相同,如abba和madam。所有镜像串,就是左右镜像之后和原
串相同,如2S和3AIAE。注意,并不是每个字符在镜像之后都能得到一个合法字符。在本题 中,每个字符的镜像如图3-3所示(空白项表示该字符镜像后不能得到一个合法字符)。
在这里插入图片描述
输入的每行包含一个字符串(保证只有上述字符。不含空白字符),判断它是否为回文 串和镜像串(共4种组合)。每组数据之后输出一个空行。

提示

  1. 既然不包含空白字符,可以安全地使用scanf进行输入。回文串和镜像串的判断都不复杂,并且可以一起完成,详见下面的代码。使用常量数组,只用少量代码即可解决这个看上去有些复杂的题目。
  2. :头文件ctype.h中定义的isalpha、isdigit、isprint等工具可以用来判断字符 的属性,而toupper、tolower等工具可以用来转换大小写。如果ch是大写字母,则ch-'A’就是 它在字母表中的序号(A的序号是0,B的序号是1,依此类推);类似地,如果ch是数字, 则ch-'0’就是这个数字的数值本身。

程序3-7 回文词

#include<stdio.h>
#include<string.h>
#include<ctype.h>
const char* rev = "A   3  HIL JM O   2TUVWXY51SE Z  8 ";
const char* msg[] = {"not a palindrome", "a regular palindrome", 
					"a mirrored string", "a mirrored palindrome"};

char r(char ch) {
  if(isalpha(ch)) return rev[ch - 'A'];
  return rev[ch - '0' + 25];
}

int main() {
  char s[30];
  while(scanf("%s", s) == 1) {
    int len = strlen(s);
    int p = 1, m = 1;
    for(int i = 0; i < (len+1)/2; i++) {
      if(s[i] != s[len-1-i]) p = 0; // 不是回文串
      if(r(s[i]) != s[len-1-i]) m = 0; // 不是镜像串
    }
    printf("%s -- is %s.\n\n", s, msg[m*2+p]);
  }
  return 0;
}

例题3-4 猜数字游戏的提示(Master-Mind Hints, UVa 340)

实现一个经典"猜数字"游戏。给定答案序列和用户猜的序列,统计有多少数字位置正确 (A),有多少数字在两个序列都出现过但位置不对(B)。
输入包含多组数据。每组输入第一行为序列长度n,第二行是答案序列,接下来是若干 猜测序列。猜测序列全0时该组数据结束。n=0时输入结束。
样例输入:
4
1 3 5 5
1 1 2 3
4 3 3 5
6 5 5 1
6 1 3 5
1 3 5 5
0 0 0 0
10
1 2 2 2 4 5 6 6 6 9
1 2 3 4 5 6 7 8 9 1
1 1 2 2 3 3 4 4 5 5
1 2 1 3 1 5 1 6 1 9
1 2 2 5 5 5 6 6 6 7
0 0 0 0 0 0 0 0 0 0
0
样例输出:
Game 1:
(1,1)
(2,0)
(1,2)
(1,2)
(4,0)
Game 2:
(2,4)
(3,2)
(5,0)
(7,0)

提示

  1. 直接统计可得A,为了求B,对于每个数字(1~9),统计二者出现的次数c1和c2,则min(c1,c2)就是该数字对B的贡献。最后要减去A的部分。代码如下:
#include<stdio.h>
#define maxn 1010

int main() {
 int n, a[maxn], b[maxn];
 int kase = 0;
 while(scanf("%d", &n) == 1 && n) { // n=0时输入结束 
   printf("Game %d:\n", ++kase);
   for(int i = 0; i < n; i++) scanf("%d", &a[i]);
   for(;;) {
     int A = 0, B = 0;
     for(int i = 0; i < n; i++) {
       scanf("%d", &b[i]);
       if(a[i] == b[i]) A++;
     }
     if(b[0] == 0) break; //正常的猜测序列不会有0,所以只判断第一个数是否为0即可 
     for(int d = 1; d <= 9; d++) {
       int c1 = 0, c2 = 0; // 统计数字d在答案序列he猜测序列中各出现多少次 
       for(int i = 0; i < n; i++) {
         if(a[i] == d) c1++;
         if(b[i] == d) c2++;
       }
       if(c1 < c2) B += c1; else B += c2;
     }
     printf("    (%d,%d)\n", A, B-A);
   }
 }
 return 0;
}

例题3-5 生成元(Digit Generator, ACM/ICPC Seoul 2005, UVa1583)

如果x加上x的各个数字之和得到y,就说x是y的生成元。给出n(1≤n≤100000),求最小 生成元。无解输出0,例如,n=216,121,2005时的解分别为198,0,1979。

提示

  1. 只需一次性枚举100000内的所有正整数m,标 记“m加上m的各个数字之和得到的数有一个生成元是m”,最后查表即可。
#include<stdio.h>
#include<string.h>
#define maxn 100005
int ans[maxn];

int main() {
  int T, n;
  memset(ans, 0, sizeof(ans));
  for(int m = 1; m < maxn; m++) {
    int x = m, y = m;
    while(x > 0) { y += x % 10; x /= 10; }
    if(ans[y] == 0 || m < ans[y]) ans[y] = m;
  }
  scanf("%d", &T);
  while(T--) {
    scanf("%d", &n);
    printf("%d\n", ans[n]);
  }
  return 0;
}

例题3-6 环状序列(Circular Sequence, ACM/ICPC Seoul 2004, UVa1584)

长度为n的环状串有n种表示法,分别为从某 个位置开始顺时针得到。例如,图3-4的环状串 有10种表示:
CGAGTCAGCT,GAGTCAGCTC,AGTCAGCTCG等。在这些表示法中,字典序最小的称 为"最小表示"。
在这里插入图片描述
输入一个长度为n(n≤100)的环状DNA串(只包含A、C、G、T这4种字符)的一种表 示法,你的任务是输出该环状串的最小表示。例如,CTCC的最小表示是 CCCT,CGAGTCAGCT的最小表示为AGCTCGAGTC。

提示

  1. 。所谓字典序,就是字符串在字典中的顺序。一般地, 对于两个字符串,从第一个字符开始比较,当某一个位置的字符不同时,该位置字符较小的 串,字典序较小(例如,abc比bcd小);如果其中一个字符串已经没有更多字符,但另一个 字符串还没结束,则较短的字符串的字典序较小(例如,hi比history小)。字典序的概念可 以推广到任意序列,例如,序列1, 2, 4, 7比1, 2, 5小。
#include<stdio.h>
#include<string.h>
#define maxn 105

// 环状串s的表示法p是否比表示法q的字典序小? 
int less(const char* s, int p, int q) 
{
  int n = strlen(s);
  for(int i = 0; i < n; i++)
    if(s[(p+i)%n] != s[(q+i)%n])
      return s[(p+i)%n] < s[(q+i)%n];//返回值有true  false的,如果满足小于,说明这个位置的取值更优。

  return 0; // 相等
}

int main() {
  int T;
  char s[maxn];
  scanf("%d", &T);
  while(T--) {
    scanf("%s", s);
    int ans = 0;
    int n = strlen(s);
    for(int i = 1; i < n; i++)
      if(less(s, i, ans)) ans = i;
    for(int i = 0; i < n; i++)
      putchar(s[(i+ans)%n]);
    putchar('\n');
  }
  return 0;
}

黄沙百战穿金甲,不破楼兰终不还。

猜你喜欢

转载自blog.csdn.net/ac1085589289/article/details/86658728
3.3
今日推荐