紫书解题报告——一定要总结经验

本文总结了第四章的算法挑战,涉及AncientCipher的字符重排、HangmanJudge的猜字游戏优化、TheDoleQueue的取模技巧等。讲解了MessageDecoding的空间节省策略,以及SpreadsheetTracking中循环和数组索引的注意事项。还分享了解决ATypicalHomework中问题的方法和Xiangqi的棋盘逻辑。
摘要由CSDN通过智能技术生成

从第四章开始,之前的都很容易一遍ac
vj紫书链接

题意请看紫书,有对应页码

第四章:函数和递归

73页 Ancient Cipher UVA - 1339

重排不仅是有无数可能,同时也是可以是不管顺序,更简单!
只有出现次数需要记录。

79 Hangman Judge UVA - 489

1.出错:
有一个记录这轮有没有找到的
故猜完了就break,后面的不要再记录了,否则win变chickened out
2.加快效率:
记录还剩下多少个,不为0继续
比检查还有没有没去掉的快

82 The Dole Queue UVA - 133

1.循环——取模运算
a[n]中第i号(从1到n)
p= (i+n-1) %n+1;
//知识:-1%n=n-1,
//考虑到1到0,转到n,不可以 p= i %n;
走过,就修改一下,以后只记没修改的就好
2.从1开始数k个,到k,2k,…,那要从0+k开始
相应的,从n开始倒数m个,到n-m+1,n-2m+1,…,那要从n+1开始
相当于哨兵节点,方便很多
(按上面取了余,则分别是n和1)

83 Message Decoding UVA - 213

1.想法:
妙,空间换时间。
直接开code [8] [1<<8] , 把目标字符串存在对应位置
2.注意换行,可把getchar()改为不读换行"\n or \r"的函数
这题挺有意思,代码:

#include<stdio.h>
#include<string.h>
//#include<math.h>
//#include<iostream>
//#include<algorithm>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
int code[8][1<<8];
int readchar()
{
	char ch;
	while(1)
	{
		ch=getchar();
		if(ch!='\n'&&ch!='\r')return ch;
	}
}
int readcode()
{
	if((code[1][0]=readchar())==EOF)return 0;
	for(int len=2;len<(1<<3);len++)
	{
		int m=(1<<len)-1;
		for(int cnt=0;cnt<m;cnt++)
		{	
			code[len][cnt]=getchar();		
			if(code[len][cnt]=='\n'||code[len][cnt]=='\r')return 1;
		}
	}
	return 1;
}
int readint(int t)
{
	int s=0;
	while(t--)
	{
		s=s*2+readchar()-'0';
	}
	return s;
}
int main()
{
	while(readcode())
	{
		for(int len=readint(3);len;len=readint(3))
		{
			for(int cnt=readint(len);cnt!=(1<<len)-1;cnt=readint(len))
			{
				putchar(code[len][cnt]);
			}
		}
		putchar('\n');
	}
	return 0;
}

85 Spreadsheet Tracking UVA - 512

1.关于重复的教训
循环内分支,比分支内循环,代码简洁不易错
如果复制粘贴,经常有的字母忘记改。只要不卡常,以后怎样copy最少用怎样,时间的常数比copy的错误危害小多了
2.关于结构下数组序号的教训
容易cmd[i].x[j]写成都是i,
或者二重循环就也错了
要注意
3.思路妙:
将所有操作保存,然后对于每个查询,对该格进行每个操作。
不需要整个电子表格一起变化,会更好写,更高效

89 A Typical Homework (a.k.a Shi Xiong Bang Bang Mang) UVA - 12412

1.建议写一段前先把想到的注意点都注下,防止分心忘记,很多就错在这里
2.//发现错误的方法:多加了几个重名人 ,即让数据更大一些
3.查询时,我用了是排名成绩的sort方法
但是错了,因为读英语有
//in the same order they’re added to the database.
紫书上是一个a[i]只用一次,不会删除后再利用解决进入时的顺序问题
//所以排序还不行,并且如果要改对,连储存方式都要改,还是看看紫书算了
//英语要好
4.浮点数误差:
When formatting a floating-point number such as Average Score, a good way to prevent floating-point errors is to add a small number (like 1e-5 in this problem). Otherwise, 80.315 would be printed
as 80.31 if the floating-point error makes it 80.31499999…
即内部存的是有误差的,四舍五入可能出错,所以要+EPS防止出错

95 Xiangqi UVA - 1589

一下午ac了,狂喜
一个我看了才找对思路的题解
开始思路:把棋盘的正在被将的点画上
麻烦:可能重叠将,可能吃子
现在思路:存棋盘,判断将走的四个点,到底能不能至少有一个躲过将军。先看是否对将注意。
具体见下,还有一个输出棋盘的注释,可以看到。
https://blog.csdn.net/sunlanchang/article/details/56682373
一个找到我错的测试数据,tql
是对将的那个发现
https://blog.csdn.net/weixin_30606669/article/details/96243267?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
一个笨笨的常见错误:在外面,命名要对到了!

简化技巧:
(简化不仅省时,而且减少复制粘贴,降低出错可能。实在不行,自己重新写,也不要复制粘贴的风险)
使用宏:
使用中等等级的宏,意思是,不要把文本改了,改了数字就好了,否则乱且报错
使用数组确定方向:可以循环了。注意马,将不共用方向为好,修改时改了马的,没想到将的就走错了。

			if(vis[i][y0]=='G'){//wa:少了一个y0的0! 
				win=0;break;//对将 
			}else if(vis[i][y0]){
				break;//不是对子 

/* POJ4001 HDU4121 UVA1589 UVALive5829 Xiangqi */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ll long long 
#define mem(a,b) memset(a,b,sizeof(a))
#define L 10
#define W 9
#define br(a,b)	if(vis[(a)][(b)]=='R')return false;else if(vis[(a)][(b)])break
#define _forplus(i,a,b) for( int i=(a); i<=(b); i++)
#define _forsub(i,a,b) for( int i=(a); i>=(b); i--)
#define bc(a,b) if(vis[(a)][(b)])\
			if(cnt==0)cnt++;\
			else if(vis[(a)][(b)]!='C')break;\
			else return false
#define bh(a,b,c,d) if((a)<1||(a)>L||(b)<1||(b)>W)continue;\
		if(vis[(a)][(b)]!='H')continue;\
		if(vis[(c)][(d)])continue;\
		return false
char vis[12][12]={0};
int x,y;
char ch;
int f[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int fx[8][4]={{-1,2,-1,1},{1,2,1,1},{2,1,1,1},
{2,-1,1,-1},{1,-2,1,-1},{-1,-2,-1,-1},{-2,-1,-1,-1},{-2,1,-1,1}};
int n,x0,y0;
int win=0;
inline char mychar(){
	int ch=getchar();
	while(ch<'A'||ch>'Z')ch=getchar();
	return ch;
}
bool can(int x,int y){
	//判断是否出界 
	if(x<1||x>3||y<4||y>6){
		return false;
	}
	//判断是否前方第一个是将 
	//同y,看x
	for(int i=x+1;i<=L;i++){
		if(vis[i][y]=='G')return false;
		else if(vis[i][y])break;
	}
	//判断是否十字第一个有车
	_forplus(i,x+1,L){
		br(i,y);
	}
	_forsub(i,x-1,1){
		br(i,y);
	}
	_forplus(j,y+1,W){
		br(x,j);
	}
	_forsub(j,y-1,1){
		br(x,j);
	}
	//判断是否十字第二个有炮
	int cnt;
	cnt=0;
	_forplus(i,x+1,L){
		bc(i,y);
	}
	cnt=0;
	_forsub(i,x-1,1){
		bc(i,y);
	}
	cnt=0;
	_forplus(j,y+1,W){
		bc(x,j);
	}
	cnt=0;
	_forsub(j,y-1,1){
		bc(x,j);
	}
	//判断是否八方有马,且不越界,不bang脚
	_forplus(i,0,7){
		bh(x+fx[i][0],y+fx[i][1],x+fx[i][2],y+fx[i][3]);
	}
	return true;
}
int main()
{
	while(~scanf("%d%d%d",&n,&x0,&y0)&&n)
	{
		//涂点,0可1不可,2落红子 
		mem(vis,0);
		for(int i=1;i<=n;i++){
			ch=mychar();
			scanf("%d%d",&x,&y);
			vis[x][y]=ch;
			
		}
		/*//看棋盘 
		printf("\n   ");
		for(int i=1;i<=9;i++){
			printf("%d",i);
		}
		putchar('\n');
		for(int i=1;i<=10;i++){
			printf("%-3d",i);
			for(int j=1;j<=9;j++){
				if(i==x0&&j==y0){
					putchar('J');continue;
				}else if(!vis[i][j]){
					putchar('-');continue;
				}
				printf("%c",vis[i][j]);
			}
			putchar('\n');
		}*/
		win=1;//红方win为1 
		_forplus(i,x0+1,L){
			if(vis[i][y0]=='G'){//wa:少了一个y0的0! 
				win=0;break;//对将 
			}else if(vis[i][y0]){
				break;//不是对子 
			} 
			
		}
		if(win==0){
			printf("NO\n");
		}else{
			//开始判断四点可否走,有一点可走则NO 
			for(int i=0;i<4;i++){
				if(can(x0+f[i][0],y0+f[i][1])){//true可走,false不可走 
					win=0;break;
				}
			} 
			printf("%s\n",(win?"YES":"NO"));
		}
	}		
	return 0;
}

————————————————
版权声明:本文为CSDN博主「出尘呢」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_51945248/article/details/115306314

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值