算法竞赛入门经典第3章习题

3-1. 得分(UVa1585)

  给出一个有O和X组成的串(长度为1~80),统计得分。每个O的得分为目前连续出现的O的个数,X的得分为0。例如,OOXXOXXOOO的得分是为1+2+0+0+1+0+0+1+2+3。按照题目说的做就行了,超简单。

#include<stdio.h>
#include<string.h>
#define Maxn 80
char s[Maxn];
int main() {
	scanf("%s", s);
	int score = 0, tot = 0;
	for(int i = 0; i < strlen(s); i++)
	{
		if(s[i]=='X')
			score = 0;
		else if(s[i]=='O')
			score++;
		tot += score;
	}
	printf("%d\n", tot);
	return 0;
}

3-2.分子量(UVa1586)

  给出一种物质的分子式(不带括号),求分子量。本题的分子式只包含4种原子,分别为C,H,O,N,原子量为12.01,1.008,16.00,14.01(单位:g/mol)。例如,C6H5OH的分子量为94.108 g/mol。按照题目做就行了。

#include<stdio.h>
#include<string.h>
#define Maxn 80
int main() {
	char s[Maxn];
	scanf("%s", s);
	float tot = 0, score = 0;
	int num;
	for(int i = 0; i < strlen(s); i++)
	{	
		
		switch(s[i])
		{
			case 'C': {score = 12.01;	break;}
			case 'H': {score = 1.008;	break;}
			case 'O': {score = 16.00;	break;}
			case 'N': {score = 14.01;	break;}
		}
		if(s[i+1] > '0' && s[i+1] <= '9')
		{
			num = s[i+1] - '0';
			i++;
		}
		tot += score * num;
		num = 1;
	}
	printf("%.3f\n", tot);
	return 0;
}

3-3 数数字(UVa1225)

  把前n(n <= 10000)个整数顺次写在一起:123456789101112...数一数0~9各出现多少次(输出10个整数,分别是0,1,2,..., 9出现的次数)。
#include<stdio.h>
#include<string.h>
#define Maxn 10005
char s[Maxn];
int a[10];
int main() {
	scanf("%s", s);
	for(int i = 0; i < strlen(s); i++)
		a[s[i]-'0'] ++;

	for(int i = 0; i < 10; i++)
		printf("%d  ", a[i]);
	printf("\n");
	return 0;
}

3-4 周期串 (Uva455)

  如果一个字符串可以由某个长度为k的字符串重复多次得到,则称该串以k为周期。例如,abcabcabcabcabc 以3为周期(注意,它也以6 和 12 为周期)。输入一个长度不超过80的字符串,输出其最小周期。解法就是: 从小到大枚举各个周期(即从1到字符串大小),一旦符合条件就立即输出。当不是周期串时输出的最小周期即为其本身长度。

#include<stdio.h>
#include<string.h>
#define maxn 101
char s[maxn];
int main() {
    scanf("%s", s);
    int i, j, flag = 1; /* i记录周期的长度, j记录第二周期开始的位置*/
    int len = strlen(s);
    for(i = 1; i <= len; i++)
        if(len % i == 0)    //字符串的长度肯定可以被周期整除
        {
            flag = 1;
            //检测是否有周期性
            for(j = i; j < len; j++)
            {
                if(s[j] != s[j%i])
                {
                    flag = 0;
                    break;
                }
            }
            if(flag)    //如果是周期,即刻跳出
                break;
        }
    printf("%d", i);
    return 0;
}


3-5 谜题(UVa227)

有一个5*5的网络,其中恰好有一个格子是空的,其他格子各有一个字母。一个有4种指令:A, B, L, R, 分别表示把空格上、下、左、右的相邻字母移到空格中。输入初始网格和指令序列(以数字0结束),输出指令执行完毕后的网络。如果有非法指令,应输出" This puzzle has no final configuration."。

执行ARRBBL0前
T R G S J
X D O K I
M   V L N
W P A B E
U Q H C F
执行ARRBBL0后
T R G S J
X O K L I
M D V B N
M P   A E
U O H C F

             解法:输入初始网格和指令序列,初始网格用二维数组表示,分别按照指令顺序进行将字母 移到空格,遇到0就结束。






#include<stdio.h>
#include<string.h>
#define n 5
char s[n][n];
int main() {
    int i, j;
    char c;
    int i_Null = 0, j_Null = 0;
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)
            {
                scanf("%c", &s[i][j]);
                if(s[i][j] == '*')
                    {i_Null = i; j_Null = j;}
            }
    fflush(stdin);
   while((c = getchar()) != EOF){
       if(c == '0') break;
       switch(c)
       {
           case 'A': {s[i_Null][j_Null] = s[i_Null-1][j_Null]; s[i_Null-1][j_Null] = '*'; i_Null--; break;}
            case 'B': {s[i_Null][j_Null] = s[i_Null+1][j_Null]; s[i_Null+1][j_Null] = '*'; i_Null++;break;}
             case 'L': {s[i_Null][j_Null] = s[i_Null][j_Null-1]; s[i_Null][j_Null-1] = '*'; j_Null--;break;}
              case 'R': {s[i_Null][j_Null] = s[i_Null][j_Null+1]; s[i_Null][j_Null+1] = '*'; j_Null++;break;}
              default: {printf("This puzzle has no final configuration."); return 0;}
       }
   }
   printf("\n");
    for(i = 0; i < n; i++) {
        for(j = 0; j < n; j++)
            printf("%c  ", s[i][j]);
        printf("\n");
    }
    return 0;
}

3-6 纵横字谜的答案(Uva232)

    输入一个r行c列(1<=r, c<=10)的网格,黑格用“*”表示,每个白格都填有一个字母。如果一个白格的左边相邻位置或者上边相邻位置没有白格(可能是黑格,也可能出了网格边界)则称这个白格是一个起始格。首先把所有的起始格按照从上到下的、从左到右的顺序编号为1,2,3,···,如图所示:
r行c列网格
1 2 3 * 4 5 6
* 7   * 8    
9     10 * 11  
12   * 13 14    
* 15 16 * 17   *
18     * 19   20
接下来要找出所有横向单词(Across)。这些单词必须从一个起始格开始,向右延伸到一个黑格的左边或者整个网格的最右边。最后找出所有竖向单词(Down)。这些单词必须从一个起始格开始,向下延伸到一个黑格的上边或者整个网格的最下行。

#include<stdio.h>
#include<string.h>
#define MAX 12
int main(void)
{
    char buf[MAX][MAX];   //用来存储字母
    int num[MAX][MAX];    //用来存储数字
    int r, c;
    int count=1, i, j;
    while(scanf("%d", &r)&&r!=0)
    {
        scanf("%d", &c);
        memset(num, 0, sizeof(num));
        for(i = 0; i < r; i++)
            scanf("%s", buf[i]);
        int m = 1;
        for(i = 0; i < r; i++)
        {
            for(j = 0; j < c; j++)
            {
                if(buf[i][j] == '*') //如果这个位置是黑格,不用填
                    continue;
                if((j-1) < 0 || buf[i][j-1] == '*' || (i-1) < 0 || buf[i-1][j] == '*')
                {   //这个位置的上面或左面是黑格或是边界,开始往num填数字
                    num[i][j] = m++;
                }
            }
        }
        if(count != 1)
            printf("\n");
        printf("puzzle #%d:\n", count++);
        printf("Across\n");
        for(i = 0; i < r; i++)
        {
            j = 0;
            while(j < c)
            {
                if(num[i][j] == 0 || buf[i][j] == '*')
                {//如果这个是黑格或中间无值格,跳过这一次
                    j++;
                    continue;
                }
                printf("%3d.%c", num[i][j], buf[i][j]);//格式需要
                j++;
                while(j < c && buf[i][j] != '*') //当输出到行结尾时结束或是黑格时
                {
                    printf("%c", buf[i][j]);
                    j++;
                }
                printf("\n");
            }
        }
        printf("Down\n");
        for(i = 0; i < r; i++)
        {
            for(j = 0; j < c; j++)
            {
                if(num[i][j]==0 || buf[i][j]=='*')
                    continue;
                printf("%3d. %c", num[i][j], buf[i][j]);
                num[i][j] = 0;
                int k = i + 1;
                while(k < r && buf[k][j] != '*')
                {
                    printf("%c", buf[k][j]);
                    num[k][j] = 0;
                    k++;
                }
                printf("\n");
            }
        }
    }
    return 0;
}

3-7 DNA序列

  输入m个长度均为n的DNA序列,求一个DNA序列,到所用序列的总Hamming距离尽量小。两个等长字符串的Hamming距离等于字符不同的位置个数,例如,ACGT和GCGA的Hamming距离为2(左数第1,4个字符不同)。
  输入整数m和n(4<=m<=50, 4<=n<=100),以及m个长度为n的DNA序列(只包含字母A,C,G,T),输出到m个序列的Hamming距离和最小的DNA序列和对应的距离。如有多解,要求为字典序最小的结,例如,对于下面5个DNA序列,最优解为TAAGATAC。
TATGATAC
TAAGCTAC
AAAGATCC
TGAGATAC
TAAGATGT


猜你喜欢

转载自blog.csdn.net/WilliamChancwl/article/details/78088750