第三章 数组和字符串(例题篇)--算法竞赛入门经典

第三章 数组和字符串(例题篇)

知识点一:蛇形填数 P40

利用边界和碰撞

#include <stdio.h>
#include<string.h>
#define max 20
int set[max][max];
int main()
{
	int n, x, y, tot = 0;
	scanf("%d", &n);
	x = -1;
	y = n - 1;
	memset(set, 0, sizeof(set));
	while (tot < n*n)
	{
		while (x + 1 < n&&!set[x + 1][y])
			set[++x][y] = ++tot;
		while (y - 1 >= 0 && !set[x][y - 1])
			set[x][--y] = ++tot;
		while (x - 1 >= 0 && !set[x - 1][y])
			set[--x][y] = ++tot;
		while (y + 1 < n&&!set[x][y + 1])
			set[x][++y] = ++tot;
	}
	for (int i = 0;i < n;i++)
	{
		for (int j = 0;j < n;j++)
		{
			printf("%2d ", set[i][j]);
		}
		printf("\n");
	}
	return 0;
}
知识点二:读取字符串 P43

1.scanf("%s",s)它会读入一个不含空格、TAB和回车符的字符串,存入字符数组s。
2.fgetc(fin),它读取一个打开的文件fin,读取一个字符,然后返回一个int值。如果文件结束,fgetc将返回一个特殊标记EOF,它并不是一个char。如果把fgetc(fin)的返回值强制转换为char,将无法把特殊的EOF和普通字符区分开。如果要从标准输入读取一个字符,可以用getchar,它等价于fgetc(stdin)。
3.fgetc和getchar将读取“下一个字符”,因此需要知道在各种情况下,“下一个字符”是哪个。如果用“scanf("%d",&n)”读取整数n,则要是在输入123后多加了一个空格,用getchar读取的将是这个空格;如果在“123”之后紧跟着换行,则读取到的将是回车符“\n”。
4.这里有个潜在的陷阱:不同操作系统的回车换行符是不一致的。Windows是“\r”和“\n”两个字符,Linux是“\n”,而MaxOS是“\r”。如果在Windows下读取Windows文件,fgetc和getchar会把“\r”“吃掉”,只剩下“\n”;但如果要在Linux下读取同样一个文件,他们会忠实地先读取“\r”,然后才是“\n”。如果编程时不注意,所写程序可能会在某个操作系统上是完美的,但在另一个操作系统上就错得一塌糊涂。应该避免在Linux下使用Windows格式的文件,但正如前面所强调过的:应该把自己的程序写得更鲁棒,即容错性更好。
5.fgets(buf,maxn,fin)读取完整的一行,其中buf声明为char buf[maxn]。这个函数读取不超过maxn-1个字符,然后在末尾添上结束符“\0”,因此不会出现越界的情况。之所以说可以用这个函数读取完整的一行,是因为一旦读到回车符“\n”,读取工作将会停止,而这个“\n”也会是buf字符串中最后一个有效字符(再往后就是字符串结束符“\0”了)。只有在一种情况下,buf不会以“\n”结尾:读到文件结束符,并且文件的最后一个不是以“\n”结尾。
6.fgets也有一个“标准输入版”gets。遗憾的是,gets和它的“兄弟”fgets差别比较大:其用法是gets(s),没有指明读取的最大的字符数。这里就出现了一个潜在的问题:gets将不停地往s中存储内容,而不管是否存储得下!在C11标准里,该函数已被正式删除。
7.C语言并不禁止程序读写“非法内存”。例如,声明的是char s[100],完全可以赋值s[10000]=‘a’(甚至-Wall也不会警告),但后果自负。

例题3-3 回文词和镜像词(Palindromes,UVa401) P48

输入一个字符串,判断它是否为回文串以及镜像串。输入字符串保证
不含数字0.所谓回文串,就是反转以后和原串相同,如abba和madam。
所有镜像串,就是左右镜像之后和原串相同,如2S和3AIAE。注意,并
不是每个字符在镜像之后都能得到一个合法字符。
输入的每行包含一个字符串(保证只有上述字符。不含空白字符),
判断它是否为回文串和镜像串(共4种组合)。每组数据之后输出一个空
行。
样例输入:
NOTAPALINDROME
ISAPALINILAPASI
2A3MEAS
ATOYOTA

#include <stdio.h>
#include<string.h>
#include<ctype.h>
/* 头文件ctype.h中定义的isalpha、isdigit、isprint等工具可以
用来判断字符的属性,而toupper、tolower等工具可以用来转换大小写。*/
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'];
   }
   else
   {
   	return rev[ch - '0' + 25];
   }
}
int main()
{
   freopen("input.txt", "r", stdin);
   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;
}
猜数字游戏的提示(Master-Mind Hints,UVa 340) P50

实现一个经典“猜数字”游戏。给定答案序列和用户猜的序列,统计有
多少数字位置正确(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

#include <stdio.h>
#define maxn 1010
int main()
{
  freopen("input.txt", "r", stdin);
  int n, a[maxn], b[maxn];
  int kase = 0;
  while (scanf("%d", &n) == 1 && n)
  {
  	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 (b[i] == a[i])
  			{
  				A++;
  			}
  		}
  		if (b[0] == 0)
  			break;
  		for (int d = 0;d <= 9;d++)
  		{
  			int c1 = 0, c2 = 0;
  			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,UVa1583) P52

如果x加上x的各个数之和得到y,就说x是y的生成元。给出
n(1<=n<=100000),求最小生成元。无解输出0。例如,n=216,121,
2005时的解分别为198,0,1979。
提示:假设所求生成元为m。不难发现m<n。为了提高效率,只需要枚举
100000内的所有正整数m,标记“m加上m的各个数字之和得到的数有一个生成元是m”,最后查表即可。

#include <stdio.h>
#include<string.h>
#define maxn 100002
int ans[maxn];
int main()
{
	freopen("input.txt", "r", stdin);
	int T, n;
	memset(ans, 0, sizeof(ans));
	for (int m = 1;m < maxn - 1;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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值