1.简单用数组存储数据
a.输出格式:%03d——整数不够三列就在前面补0
b.几种输入函数:
scanf("%s")输入字符串碰到空格或者TAB就会停下来
解决办法1:可使用fgetc(fin)可以从打开的文件fin中读取一个字符。 一般情况下应当在检查它不是EOF后再将其转换成char值。
从标准输入读取一个字符可以用getchar,它等价于fgetc(stdin)。
注意:fgetc和getchar将读取“下一个字符”,因此需要知道在各种情况下,“下一个字符”是哪个。
解决办法2:使用“fgets(buf, maxn, fin)”读取完整的一行,其中buf的声明为char buf[maxn]。 这个函数读取不超过maxn-1个字符,然后在末尾添上结束符“\0”,因此不会出现
越界的情况。一旦读到回车符“\n”,读取工作将会停止,而这个“\n”也会是buf字符串中最后一个有效字符(再往后就是字符串结束符“\0”了)。 只有在一种情况下,buf不会以“\n”结尾:读到文件结束符,并且文件的最后一个不是以“\n”结尾。 当一个字符都没有读到时,fgets返回NULL。
注意:gets已经被废除了,但为了向后兼容,仍然可以使用它。 从长远考虑,最好不要使用此函数。
eg:蛇形填数。 在n×n方阵里填入1,2,…,n×n,要求填成蛇形。
#include<stdio.h>
#include<string.h>
#define maxn 20
int a[maxn][maxn];
int main()
{
int n,x,y,tot = 0;
scanf("%d",&n);
memset(a,0,sizeof(a));
tot = a[x= 0][y = n-1] =1;
while(tot < n*n)
{
while(x + 1 < n && !a[x+1][y]) a[++x][y] = ++tot;// “&&”是短路运算符, 如果x+1<n为假,将不会计算“!a[x+1][y]”
while(y - 1 >= 0 && !a[x][y-1]) a[x][--y] = ++tot;//走迷宫时,通过数组来确定走的方向
while(x - 1 >= 0 && !a[x-1][y]) a[--x][y] = ++tot;
while(y + 1 < n && !a[x][y+1]) a[x][++y] = ++tot;
}
for(x = 0;x < n;x ++)
{
for(y = 0;y < n;y ++)
{
printf("%3d",a[x][y]);
}
printf("\n");
}
return 0;
}
eg:竖式问题。 找出所有形如abc*de(三位数乘以两位数)的算式,使得在完整的竖式中,所有数字都属于一个特定的数字集合。 输入数字集合(相邻数字之间没有格),输出所有竖式。 每个竖式前应有编号,之后应有一个空行。 最后输出解的总数。
#include<stdio.h>
#include<string.h>
int main()
{
int count = 0;
char s[20],buf[99];
scanf("%s",s);
for(int abc = 111;abc <= 999;abc ++)
{
for(int de = 11;de <= 99;de ++)
{
int x = abc * (de%10),y = abc * (de/10),z = abc * de;
sprintf(buf,"%d%d%d%d%d",abc,de,x,y,z);//输出到字符串
int ok = 1;
for(int i = 0;i < strlen(buf);i ++)
{
if(strchr(s,buf[i]) == NULL) //返回buf[i]在s中第一次出现的位置的指针
ok = 0;
}
if(ok)
{
printf("<%d>\n",++ count);
printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n",abc,de,x,y,z);
}
}
}
printf("The number of solutions = %d\n",count);
return 0;
}
eg:实现一个经典"猜数字"游戏。 给定答案序列和用户猜的序列,统计有多少数字位置正确(A),有多少数字在两个序列都出现过但位置不对(B)。
直接统计可得A,为了求B(不用0-9的数组判断是否有相同数字是因为同一组也有重复的。),对于每个数字(1~9),统计二者出现的次数c1和c2,则min(c1,c2)就是该数字对B的贡献。 最后要减去A的部分。
#define maxn 1010
{
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(a[i] == b[i])
A ++;
}
if(b[0] == 0)break;
for(int d = 1;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)",A,B-A);
}
}
return 0;
}
2.用数组自己做表格
a.已知完整的、数据之间关系没有规律的一组数,实现用数组记录:
eg:把手放在键盘上时,稍不注意就会往右错一位。 这样,输入Q会变成输入W,输入J会变成输入K等。
#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;
}
eg:回文串和镜像串(事先把各个字母、数字的回文,镜像字符准备好,以便后来查找。
#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"};
{
if(isalpha(ch))
return rev[ch-'A'];
else
return rev[ch-'0'+25];
}
{
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;
}
eg:如果x加上x的各个数字之和得到y,就说x是y的生成元。 给出n(1≤n≤100000),求最小生成元。 无解输出0。如:198 = 198+1+ 9 + 8 = 216
一次性枚举100000内的所有正整数m,标记“m加上m的各个数字之和得到的数有一个生成元是m”,最后查表即可。
#include<string.h>
#define maxn 100005
int ans[maxn];
{
int T,n;
memset(ans,0,sizeof(ans));
for(int m = 1;m < maxn;m ++) //m是n的生成元,数组按n排序
{
int x = m,y = m;
while(x > 0)
{
y += x % 10;
x /= 10;
}
if(ans[y] == 0 || m < ans[y])//m是n的最小生成元
ans[y] = m;
}
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
printf("%d\n",ans[n]);
}
return 0;
}
3.用循环数组寻找特定排序(使用指针可以不用新建数组)
eg:输入一个长度为n(n≤100)的环状DNA串(只包含A、 C、 G、 T这4种字符)的一种表示法,你的任务是输出该环状串的最小表示。 例如,CTCC的最小表示是
CCCT,CGAGTCAGCT的最小表示为AGCTCGAGTC(字典序: 对于两个字符串,从第一个字符开始比较,当某一个位置的字符不同时,该位置字符较小的串,字典序较小(例如,abc比bcd小);如果其中一个字符串已经没有更多字符,但另一个字符串还没结束,则较短的字符串的字典序较小(例如,hi比history小)。
#include<string.h>
#define maxn 105
{
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];
return 0;
}
{
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;
}
eg:找星星(每颗星星有6条边,假设每条边的长度量化为[1,100w],现在有N(1<N<10w)颗星星,请判断是否存在相同的星星。
相同的条件为:6条边的长度依次相等(包括顺时针相等和逆时针相等)。)
{
for(int j = 0;j < 6;j ++)
{
bool flag = true;
for(int i = 0;i < 6;i ++)
if(star[k].length[i] != p->length[(i+j)%6])
{
flag = false;
break;
}
if(flag)
return true;
}
return false;
}
{
for(int j = 0;j < 6;j ++)
{
bool flag = true;
for(int i = 0;i < 6;i ++)
if(star[k].length[i] != p->length[(11-i-j)%6])
{
flag = false;
break;
}
if(flag)
return true;
}
return false;
}