算法练习2
int a[maxn],包含maxn个数组,不包含a[maxn]
a[n++]=x可以改成
{a[n++]=x;n=n+1}
只有把数组放在main,数组才可以开的很大,否则程序可能崩溃
从数组a复制K个元素到数组b
memcpy(b,a,sizeof(int)*k) (需要使用头文件string.h)
全部复制则为memcpy(b,a,sizeof(a))。
有n盏灯,编号为1~n,第1个人把所有灯打开,第2个人按下所有编号为2的倍数的开关(这些灯将被关掉),第3个人按下所有编号为3的倍数的开关(其中关掉的灯被打开, 开着灯将被关闭),依此类推。一共有k个人,问最后有哪些灯开着?
输入:n和k,输出开着的灯编号。k≤n≤1000。
样例输入:7 3
样例输出:1 5 6 7
结题思路:
定义一个数组,下标代表灯的编号,利用双循环对数组赋值,比如,第一个人把所有灯打开,所有赋值为1,第二个人,把2的倍数的灯再加1,第三个人把3的倍数的灯加1,灯的开关与下表对应的数的奇偶性相关,奇数表示灯开,偶数表示灯关。。
代码如下:
- #include<stdio.h>
- #include<string.h>
- #include<stdlib.h>
- int main()
- {
- int n,k,i,j,a[1100];
- while(scanf("%d%d",&n,&k)!=EOF)
- {
- memset(a,0,sizeof(a));//数组要清零
- for(i=1;i<=k;i++)
- {
- for(j=1;j<=n;j++)
- {
- if(j%i==0)
- {
- a[j]++;
- }
- }
- }
- for(j=1;j<=n;j++)
- {
- if(a[j]&1)
- printf("%d ",j);
- }
- printf("\n");
- }
- return 0;
- }
#include <stdio.h>
#include <string.h>
#define MAXN 1000 + 10
//数组开的大一点
int a[MAXN];
//在c语言里面是非零即真,!的意思是取反,这题的意思将为0的数取为1,将不为1的数赋值为0
int main(int argc, char *argv[])
{
int n, k, first = 1;
scanf("%d %d", &n, &k);
memset(a, 0, sizeof(a));
//把数组a清零
for(int i = 1; i <= k; i++)
for(int j = 1; j <= n; j++)
{
if(j%i == 0) a[j] = !a[j];
}
/*
为了避免输出多余空格,设置一个标志变量first
,可以表示当前要输出的变量是否为第一个,第一个变量
前不应该有空格。其他变量都有。
*/
for(int j = 1; j <= n; j++)
if(a[j] == 1) {
if(first) first = 0;
else printf(" ");
printf("%d", j);
}
printf("\n"); //最后再输出换行符
return 0;
}
2.蛇形填数
在n*n方阵里填入1,2,„,n*n,要求填成蛇形。例如n=4时方阵为
10 11 12 1
9 16 13 2
8 15 14 3
7 6 5 4
上面的方阵中,多余的空格只是为了便于观察规律,不必严格输出。n≤8。
分析类比数学中的矩阵,可以用一个二位数组来出储存题目中的方阵,int[maxn][maxm],,就可以获得一个方阵,
思路:
从一开始依次填写,设“笔”的坐标为(x,y),则一开始x=0,y=n-1,笔的移动轨迹是:下下下,左左左,上上上,右右,下下,左,上。总之,先是向下,然后到不能填为止,“不能填”是指再走就出界。
代码:
#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;
}
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;
}
附上另一种解法
#include<stdio.h>
int main()
{
int a,b,c,d,n,sum=1;
int yi[101][101];
scanf("%d",&n);
for(a=0;a<=(n-1)/2;a++)
{
for(b=a;b<=n-a-1;b++)
yi[b][n-a-1]=sum++;
for(b=n-2-a;b>=a;b--)
yi[n-a-1][b]=sum++;
for(b=n-a-2;b>=a;b--)
yi[b][a]=sum++;
for(b=a+1;b<n-a-1;b++)
yi[a][b]=sum++;
}
for(c=0;c<n;c++)
{
for(d=0;d<n;d++)
printf("%d ",yi[c][d]);
printf("\n");
}
}
3.竖式问题
题目:找出所有形如abc*de(三位数乘以两位数)的算式,使得在完整的竖式中,所有数字都属于一个特定的数字集合。输入数字集合(相邻数字之间没有空格),输出所有竖式。每个竖式前应有编号,之后应有一个空行。最后输出解的总数。具体格式见样例输出(为了便于观察,竖式中的空格改用小数点显示,但你的程序应该输出空格,而非小数点)。样例输入:2357样例输出:<1>..775X..33-----.23252325.-----25575The number of solutions = 1
分析:
这题类似于一个乘法的过程,主要是输出格式上的要求。
代码:
#include<stdio.h>
#include<string.h>
int main()
{
int abc, de, x, y, z, i, ok, count = 0;
char s[20], buff[100];
scanf("%s", s);
for (abc = 111; abc < 999; abc++)
{
for (de = 11; de < 99; de++)
{
x = abc * (de % 10);
y = abc * (de / 10);
z = abc * de;
sprintf(buff, "%d%d%d%d%d", abc, de, x, y, z); //把这五个数字作为字符放入buff数组中 ,连接为一条字符串
ok = 1;
for (i = 0; i < strlen(buff); i++)
if (strchr(s, buff[i]) == NULL)
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;
}
/*
函数功能:把格式化的数据写入某个字符串
函数原型:int sprintf( char *buffer, const char *format [, argument] … );
返回值:字符串长度(strlen)
例子:
char* who = "I";
char* whom = "****";
sprintf(s, "%s love %s.", who, whom); //产生:"I love ****. " 这字符串写到s中
strchr函数原型:
char * strchr(char * str, int ch);
功能就是找出在字符串str中第一次出项字符ch的位置,
找到就返回该字符位置的指针(也就是返回该字符在字符串中的地址的位置),
找不到就返回空指针(就是 null)。
*/
4.TeX中的引号在Tex中,做双引号的" `` ",右双引号是" '' "(两个回车左边的).输入一篇包含双引号的文章,你的任务是把它转换成TeX的格式。
样例输入:"To be or not to be,"quoth the Bard,"that
``To be or not to be''quoth the Bard,``that
//fgetc(fin),读取一个打开的文件,读取一个字符,然后返回一个int值,文件结束返回一个特殊标记EOF,它并不是一个char;可以用getchar,等价于fgetc(stdin)
#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;
}
5.WERTYU输入一个错位后敲出的字符串(所有字母均大写),输出打字员本来想打出的句子。输入保证合法,即一定是错位之后的字符串。例如输入中不会出现大写字母A。
样例输入:
O S, GOMR YPFSU/
样例输出:
I AM FINE TODAY.
【分析】
(C语言中)每输入一个字符,都可以直接输出一个字符,因此getchar是输入的理想方法。问题在于:如何进行这样输入输出变换呢?一种方法是使用if语句或者switch语句,如”if(c == 'W') putchar('Q')“。但很明显,这样做太麻烦。一个较好的方法是使用常量数组。
用C语言编写程序,代码如下:
#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;
}
回文词(Palindromes, UVa401)
输入一个字符串,判断它是否为回文串以及镜像串。输入字符串保证不含数字0。所谓回文串,就是反转以后和原串相同,如abba和madam。所有镜像串,就是左右镜像之后和原串相同,如2S和3AIAE。注意,并不是每个字符在镜像之后都能得到一个合法字符。在本题中,每个字符的镜像如图3-3所示(空白项表示该字符镜像后不能得到一个合法字符)。
输入的每行包含一个字符串(保证只有上述字符。不含空白字符),判断它是否为回文串和镜像串(共4种组合)。每组数据之后输出一个空行。
样例输入:
NOTAPALINDROME
ISAPALINILAPASI
2A3MEAS
ATOYOTA
样例输出:
NOTAPALINDROME – is not a palindrome.
ISAPALINILAPASI – is a regular palindrome.
2A3MEAS – is a mirrored string.
ATOYOTA – is a mirrored palindrome.
代码:
#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'];//判断ch是否为字母
else return rev[ch-'0'+25];
}
int main() {
char s[30];
int i = 0;
while((scanf("%s", s)) == 1) {
int len = strlen(s);
int p = 1, m = 1;
for(i = 0; i < len/2; ++i) {
if(s[i] != s[len-i-1]) p = 0;//回文数
if(r(s[i]) != s[len-i-1]) m = 0;//镜像数
}
printf("%s -- is %s.\n\n", s, msg[2*m+p]);
}
return 0;
}
//本题使用了一个自定义函数char r(char ch)参数ch是一个字符,返回值是ch的镜像字符。
//本题用isalpha来判断字符是否为字母,需要头文件ctype.h
7.
实现一个经典“猜数字”游戏。给定答案序列和用户猜的序列,统计有多少数字位置正确(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)
分析:数字在两个序列都出现过但是位置不对指的是:数字在两个序列都出现了,在对应位置上都没有相同的,即不属于A情况,
直接统计可得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在答案序列和猜测序列中各出现多少次
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;
}