算法竞赛入门经典第4章 【uvaoj习题(一)】

题目合集

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94


uva10055

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=996

“ These two numbers in each line denotes the number of soldiers in Hashmat's army and his opponent's army or vice versa.”

注意到vice versa这个题目就可以过了,英文阅读能力啊

#include <stdio.h>

int
main(void)
{
	long long a, b;

	while (scanf("%lld %lld", &a, &b) != EOF) {
		printf("%lld\n", a>b ? a-b : b-a);
	}
	return 0;
}


uva10071

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=1012

#include <stdio.h>

int
main(void)
{
	int v, t;

	while (scanf("%d %d", &v, &t) != EOF)
		printf("%d\n", v*t*2);
	return 0;
}


uva100300

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=1241

按题意有一个(a/b)*b*c的过程,因此要写成a*c

#include <stdio.h>

int
main(void)
{
	int tc, x, a, b, c;
	int permium;

	scanf("%d", &tc);
	while (tc--) {
		scanf("%d", &x);
		permium = 0;
		while (x--) {
			scanf("%d %d %d", &a, &b, &c);
			permium += a*c;
		}
		printf("%d\n", permium);
	}
	return 0;
}


uva458

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=399

其实就是除了换行符,其他字符都作一个相对平移后输出

#include <stdio.h>

int
main(void)
{
	int c;

	while ((c = getchar()) != EOF)
		putchar(c == '\n' ? '\n' : c-('1'-'*'));
	return 0;
}



uva494

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=435

用ctype.h写出来的程序可读性比较好哦

注意fgets的用法,遇到回车符就停止读取,并且把回车符读入,这个gdb可以查看,遇到EOF会返回NULL

虽然str的值等于str[0],但是sizeof 这个两个东西结果是不同的。可以想象str是一个包含整个数组的长方框,而str[0]是一个元素的单位方框,sizeof关键词返回的是单位方框数

#include <stdio.h>
#include <ctype.h>
#define N 10000
char str[N];

int
main(void)
{
	char *p = NULL;
	int count;
	
	while (fgets(str, sizeof (str), stdin) != NULL) {
		count = 0;
		for (p = str; *p != '\n'; p++) {
			if (isalpha(*p) && !isalpha(*(p+1)))
				count++;
		}
		printf("%d\n", count);
	}
	return 0;
}


uva414

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=355

这个英语阅读也略吃力,看到几遍才完全看懂,意思就是两边的图形(由"X"组成)相遇或说相连时,空白符还剩下多少?

思路就是必定有一行或多行最先相遇,这些行的空白符数量最少。那么求出矩阵所有的空白符数量,再减去行数*对所有行的空白符数量数组升序排序后的spacenum[0],就是答案了

注意示例是'B'代替了' ',因此测试时改成'B',提交时改回' '

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define X 30
#define Y 15

/*
 出错的地方是:memset(spacenum, 0, sizeof (int));
 第二次循环时只初始化了第一个元素,第一次循环全局数组本来就被置为0
 注意关键字sizeof 是求一块存储空间的块数
 fgets的格式 ex.sizoef (str)
 memset的格式 ex. sizeof (str)
 qsort的格式 ex.sizeof (int)
 */

char str[Y][X];
int spacenum[Y];

int
cmp(const void *a, const void *b)
{
	return *(int *)a - *(int *)b;
}

int
main(void)
{
	int row;
	int i, j;
	int sum;
	
	while (scanf("%d%*c", &row)) {
		if (row == 0)
			break;
		sum = 0;
		memset(spacenum, 0, sizeof(spacenum));
		for (i = 0; i != row; i++) {
			fgets(str[i], sizeof (str[i]), stdin);
			for (j = 0; str[i][j] != '\n'; j++) {
				if (str[i][j] == ' ') {
					spacenum[i]++;
				}
			}
			sum += spacenum[i];
		}
		qsort(spacenum, row, sizeof (int), cmp);
		printf("%d\n", sum - row*spacenum[0]);
	}
	return 0;
}


uva490

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=431

这个题目没讲清楚,其实说白了可以是输入几行字符串到一个全是空白符的字符矩阵中,然后右旋这个含有当前输入字符串的最小矩阵

可以用结构体也可以用二维数组,结构体看上去或者会更清晰,但比较啰嗦

#include <stdio.h>
#define N 110

typedef struct node {
	char str[N];
}node;

node a[N];
char *p[N];

int
main(void)
{
	int i = 0, j;		
	while (fgets(a[i].str, sizeof (a[i].str), stdin) != NULL) {
		i++;
	}
	for (j = 0; j != i; j++) {
		p[j] = a[i-1-j].str;
	}
	while (1) {
		for (j = 0; j != i; j++) {
			if (*p[j] == '\n')
				printf(" ");
			else
				printf("%c", *p[j]++);
		}
		for (j = 0; j != i; j++) {
			if (*p[j] != '\n')
				break;
		}
		printf("\n");
		if (j == i)
			break;
	}
	return 0;
}


uva445

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=386

按照条件进行输出,如果是数字就一直叠加,这个数字的意思是输出后面字符(字母集合并上{'*'})的次数。而且如果输入的是'b'要对应输出' '。

#include <stdio.h>
#include <ctype.h>
#define N 150

char str[N];

int
main(void)
{
	char *p = NULL;
	int times;
	int i;
	
	while (fgets(str, sizeof (str), stdin) != NULL) {
		times = 0;
		for (p = str; *p != '\n'; p++) {
			if (isdigit(*p)) {
				times += *p - '0';
			}
			if (isalpha(*p) || '*' == *p) {
				for (i = 0; i != times; i++)
					printf("%c", *p == 'b' ? ' ' : *p);
				times = 0;
			}
			if ('!' == *p)
				printf("\n");
		}
		printf("\n");
	}
	return 0;
}


uva488

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=429

这个题目坑的地方是,只是最后一组测试数据的最后一个波才不需要输出空行,比如共3组测试数据,第2组数据输出4个波,第4个波也是要输出空行的

#include <stdio.h>

int
main(void)
{
	int tc;
	int a, f;
	int i, j;
	int tmp;

	scanf("%d", &tc);
	while (tc--) {
		scanf("%d %d", &a, &f);
		while (f--) {
			for (i = 1; i != 2*a; i++) {
				tmp = i > a ? 2*a-i : i;
				for (j = 0; j != tmp; j++) {
					printf("%d", tmp);
				}
				printf("\n");
			}
			if (!(0 == tc && 0 == f)) //Notice!!!
				printf("\n");
		}
	}
	return 0;
}

uva489

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=430

用了一个傻X方法一次AC,好的方法看第二段代码

这个题目还是考了点逻辑,只要把逻辑理清按部就班就不会出错。

傻X方法就是猜的字母在给定字符中寻找,找到了并且是之前没有猜过,那么胜利参数才会加1,如果搜寻完毕还是没有找到,那么失败参数加1

#include <stdio.h>
#include <string.h>
#define N 200
#define M 27
char s_str[N];
char g_str[N];

typedef struct node {
	char alpha;
	int isexist;
	int isguessed;
}node;

node list[M];

void
guess(int key, int *w, int *l)
{
	int i;

	for (i = 0; i != M; i++) {
		if (list[i].isexist && list[i].alpha == key && !list[i].isguessed) {
			(*w)++;
			list[i].isguessed = 1;
			break;
		}
	}
	if (i == M) {
		(*l)++;
	}
}

int
main(void)
{
	int round;
	int i;
	char *p, *q;
	int win_c, lose_c;
	int count;

	while (scanf("%d", &round)) {
		if (-1 == round)
			return 0;
		scanf("%s %s", s_str, g_str);
		count = 0;
		win_c = 0;
		lose_c = 0;
		
		for (i = 0; i != M; i++) {
			list[i].alpha = 'a'+i;
			list[i].isexist = 0;
			list[i].isguessed = 0;
		}
		
		for (p = s_str; *p != '\0'; p++) {
			for (i = 0; i != M; i++) {
				if (*p == list[i].alpha && !list[i].isexist) {
					list[i].isexist = 1;
					count++;
				}
			}
		}
		
		for (q = g_str; *q != '\0'; q++) {
			guess(*q, &win_c, &lose_c);
			if (win_c == count) {
				printf("Round %d\n", round);
				printf("You win.\n");
				break;
			}
			if (lose_c == 7) {
				printf("Round %d\n", round);
				printf("You lose.\n");
				break;
			}
		}
		if (*q == '\0') {
			printf("Round %d\n", round);
			printf("You chickened out.\n");
		}
	}
	return 0;
}

好的方法应该是:

直接建立一个存入给定字符串不同字符的新字符串S,并且统计了不同的字符有多少个

然后猜的字符串中,重复的应该去掉,但是注意重复的那部分字符如果是猜对了,那么胜利因素是不会增加,而如果是猜错了,那么失败因素是会增加的

因此猜的字符串中分成两部分,不重复的一部分,重复的一部分,重复搜索S,找不到失败因素+1;不重复的找到了胜利因素+1,否则失败因素+1;


uva694

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=635

为什么把a搞成long long int类型呢?考虑到虽然a保证是在int范围,但是有一个3*a+1的过程,这个可能导致溢出。因此不管那么多,果断采用long long int;

【陷阱】这种数据在运算过程中的溢出是非常恐怖的。比如之前的二分查找,mid = (a+b)/2,传入的参数可以保证不溢出,但是a+b就可能溢出了。。。

#include <stdio.h>

int
main(void)
{
	long long a, save_a;
	int	lim, count;
	int tc = 0;
	
	while (scanf("%lld %d", &a, &lim)) {
		if (-1 == a && -1 == lim)
			break;
		save_a = a;
		count = 1;
		while (a != 1) {
			if (a % 2 == 0) {
				a = a/2;
			}
			else {
				a = 3*a+1;
			}
			if (a > lim)
				break;
			count++;
		}
		printf("Case %d: ", ++tc);
		printf("A = %lld, limit = %d, number of terms = %d\n", save_a, lim, count);
	}
	return 0;
}


uva457

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=show_problem&problem=398

这题目考英文阅读能力啊,看得我十分蛋疼!!!很少人提交的原因估计就是英文没看懂

顺带学几个术语吧

culture dish 培养皿

population density 种群密度/浓度?

题目意思是:

第一天之后的培养皿中【菌体浓度】:PD=DNA[S],S等于前一天当前培训皿的PD和直接相邻培训皿的PD三者之和

而且规定最右(左)边的右(左)邻培养皿(不存在)的PD = 0

因此输出的矩阵,列是从1~40的,开的数组尽量大些

#include <stdio.h>
#include <string.h>
#define X 50
#define Y 60
#define N 10

int DNA[N];
char PD[Y][X];

int
main(void)
{
	int tc;
	int i, j;

	scanf("%d", &tc);
	while (tc--) {
		for (i = 0; i != N; i++) {
			scanf("%d", &DNA[i]);
		}
		memset(PD, 0, sizeof (PD));
		PD[0][20] = 1;
		for (i = 0; i != 50; i++) {
			for (j = 1; j != 41; j++) {
				PD[i+1][j] = DNA[ PD[i][j]+PD[i][j-1]+PD[i][j+1] ];
				switch(PD[i][j]) {
				case 0:
					printf(" ");
					break;
				case 1:
					printf(".");
					break;
				case 2:
					printf("x");
					break;
				case 3:
					printf("W");
					break;
				}
			}
			printf("\n");
		}
		if (tc != 0) {
			printf("\n");
		}
	}
	return 0;
}

输入

1

0 1 2 0 1 3 3 2 3 0

输出

                   .                    
                  ...                   
                 .x x.                  
                .  .  .                 
               .........                
              .x       x.               
             .  x     x  .              
            ...xxx   xxx...             
           .x .WW.x x.WW. x.            
          .   .xxW . Wxx.   .           
         ... . WxW...WxW . ...          
        .x xx..WWWW WWWW..xx x.         
       .  ..W.Wx  WWW  xW.W..  .        
      ....xWWxWWx W W xWWxWWx....       
     .x  .WWWWWWWW W WWWWWWWW.  x.      
    .  x..x      WW WW      x..x  .     
   ...x .. x     WWWWW     x .. x...    
  .x .  xx xx    W   W    xx xx  . x.   
 .   ..x.....x           x.....x..   .  
... .x...   . x         x .   ...x. ... 
x xx .. x. .. xx       xx .. .x .. xx x.
x... xx   xxx ..x     x.. xxx   xx ...  
 . x ..x x.W. x. x   x .x .W.x x.. x x. 
.. x x. . WW.    xx xx    .WW . .x x.  .
xx x.  x..Wx..  x.....x  ..xW..x  .  ...
...  .x .WWW.x.x .   . x.x.WWW. x....x x
x x..   .x xW.W  .. ..  W.Wx x.  .  . .x
x. .x. .  .WWx. .xxxxx. .xWW.  ......x  
  x . x....xWW x WWWWW x WWx...x    . x 
 xx .  .  .WWWWxWW   WWxWWWW. . x  .. xx
x.. .......x  WWWW   WWWW  x.x. xx.xx ..
 .xxx     . x W  W   W  W x W.  .WWW. xx
. WW.x   .. xW           WxW.....x x. ..
..WxW x .xx WW           WWWW   . .  xxx
xWWWWWx  W.WWW           W  W  ..x..x.W.
WW   WWx .xx W                .x.....WW.
WW   WWW  W.W                . ..   Wxx.
WW   W W  .x.               ..xxx.  WxW 
WW    W  . . .             .x.WWW . WWW 
WW      ..x.x..           . .Wx W...W W 
WW     .x..W..x.         ..x.WWW.W W.W  
WW    . ..WWW.. .       .x..Wx xx.W.x.  
WW   ..xxWx xWxx..     . ..WWW..WWWW. . 
WW  .x.WxxW.WxxW.x.   ..xxWx xWWx  x.x..
WW . .WWxxWxWxxWW. . .x.WxxW.WWWWxx W..x
WW..x.xWxxxWxxxWx.x.x .WWxxWxx  Wx.W.W. 
WxW..WWxxWxxxWxxWW.W  .xWxxxx.x WWWWxW..
WWWWWxWxxxxWxxxxWxx. . WxxWWWW WW  WWWWx
W   WWxxWWxxxWWxxxW x..WxxW  WWWW  W  WW
    WWxxWWxWxWWxWxWW .WWxxW  W  W     WW

这个效果挺好看的,W表示浓度最强,x次之,.最小。可以很清晰地看出细菌具备该DNA,在培养皿中50天的变化情况


【小结】

1、memset()好用,包括多维数组(其实并没有真正的多维),sizeof关键字求空间块数;

2、多用库函数和谓词函数;程序可读性包括:程序逻辑清晰,自注释语句多,库函数和谓词函数使用合理

3、qsort()中参数包括:待排的元素数量和sizeof取的单元元素所占空间的大小(字节数),比如sizeof(int); sort()是sort(a, a+n);

4、fgets()和scanf()读入字符句子的区别,前者是字符+'\n';后者是真正的字符串;

5、【陷阱】+ * 导致运算中途数据溢出;因此要变换式子的运算顺序或者换数据类型;

6、【陷阱】哪里需要换行?读清题意;输出很多文字时一定要采用复制而不是手打,否则可能WA到你崩溃;

7、按自己习惯的逻辑形式走,比如||表示两个集合的并,如果取相反情况,直接在该条件前取非;



你可能感兴趣的:(算法竞赛入门经典第4章 【uvaoj习题(一)】)