算法练习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,灯的开关与下表对应的数的奇偶性相关,奇数表示灯开,偶数表示灯关。。

代码如下:

  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<stdlib.h>  
  4. int main()  
  5. {  
  6.     int n,k,i,j,a[1100];  
  7.     while(scanf("%d%d",&n,&k)!=EOF)  
  8.     {  
  9.         memset(a,0,sizeof(a));//数组要清零   
  10.         for(i=1;i<=k;i++)  
  11.         {  
  12.             for(j=1;j<=n;j++)  
  13.             {  
  14.                 if(j%i==0)  
  15.                 {  
  16.                     a[j]++;  
  17.                 }  
  18.             }  
  19.         }  
  20.         for(j=1;j<=n;j++)  
  21.         {  
  22.             if(a[j]&1)  
  23.               printf("%d ",j);  
  24.         }  
  25.         printf("\n");  
  26.     }  
  27.     return 0;  
  28. }  
第二种解法:


#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>
..775
X..33
-----
.2325
2325.
-----
25575
The 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

                   is the question".
样例输出:
                

``To be or not to be''quoth the Bard,``that

                   is the question''.

//fgetc(fin),读取一个打开的文件,读取一个字符,然后返回一个int值,文件结束返回一个特殊标记EOF,它并不是一个char;可以用getchar,等价于fgetcstdin

#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
把手放在键盘上时,稍不注意就会往右错一位。这样,输入Q会变成输入W,输入J会变成输入K等。
       输入一个错位后敲出的字符串(所有字母均大写),输出打字员本来想打出的句子。输入保证合法,即一定是错位之后的字符串。例如输入中不会出现大写字母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;

}


6.

回文词(Palindromes, UVa401)

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

算法练习2

输入的每行包含一个字符串(保证只有上述字符。不含空白字符),判断它是否为回文串和镜像串(共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 rchar 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;

}