算法竞赛入门经典(第2版)-刘汝佳-第四章解题源码(C语言)(部分)

例题4-1

问题提出:已知:两个字符数组,经过两个操作后:1.调换顺序,2.一一映射。问通过这两个操作两个数组是否能一样。

问题分析:如果直接做,先经过随机调换再进行随机映射,显然这样很难解决这个问题,这就需要推导出字符数组1经过这两个操作后变为数组2的充要条件。

当然,想要推导有些困难,我们就只能采用猜想的方式进行猜测这个条件,然后通过理论推导或者大规模实验进行证明。

问题转化:如果字符数字1和字符数组2中字母的个数能够对应起来(比如字符数组1有5个A,2个C。而字符数组中有2个D,5个E,那么5==5,2==2),就能将字符数组1变为字符数组2.

解决方案:1.统计字符数组1和字符数组2中各个字母的个数。

                    2.对个数进行比较。看是否能满足条件。在这里,采用先排序,再比较的方式,降低复杂度。

补充说明:源码中采用了书中的排序函数qsort,实际上这个排序函数并不好,不建议以后使用。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//#define Local 

int cmp(const void *a,const void *b)
{
	return *(int*)a - *(int*)b;//升序排序, 
	//return *int( *)b-*int( *)a;//降序排序。 
	
}
int main()
{ 
	//#ifdef Local
	//	freopen("datain.txt","r",stdin);
	//	freopen("dataout.txt","w",stdout);
	//#endif
	char input1[100],input2[100];
	while(scanf("%s",input1)!=EOF&&input1)
	{
		scanf("%s",input2);
		int alphabet1[26],alphabet2[26];
		int lenthinput1,lenthinput2,flag=1;
		memset(alphabet1,0,sizeof(alphabet1));
		memset(alphabet2,0,sizeof(alphabet2));
		lenthinput1=strlen(input1);
		lenthinput2=strlen(input2);
		for(int i=0;i<lenthinput1;i++)
		{
			alphabet1[int(input1[i]-'A')]++;
		}
		for(int i=0;i<lenthinput2;i++)
		{
			alphabet2[int(input2[i]-'A')]++;
		}
		qsort(alphabet1,26,sizeof(int),cmp);
		qsort(alphabet2,26,sizeof(int),cmp);
		for(int i=0;i<26;i++)
		{
			if(alphabet1[i]!=alphabet2[i])
			{
				flag=0;
				break;
			}	
		}
		if(flag)
		printf("YES\n");
		else 
		printf("NO\n");
		
		
		
	}
	
	return 0;
} 

例题4-2

问题提出:已知答案和猜测两个字符数组,通过比对猜测数组和答案数组中的字符,判断是否猜对?

问题分析:如果要猜测对,需要满足:

1.猜测数组中有答案数组中的全部字符。

2.猜测数组中在猜对最后一个字符之前,错误的字符小于7.

那么猜测错,必须满足

1.猜测数组在猜对最后一个字符之前,错误字符大于7。

那么没有猜测对,也没有猜测错。就为待定状态

解决方案:两个角度

1.用答案数组比对猜测数组

2.用猜测数组比对答案数组。

本编码采用角度2.

补充说明:1、本题和猜测数组的顺序有关系,不能像习题4-1那样可以先统计再判断。

                    2、UVA的debug数据有问题。不适合测试

时间2014/6/20

#include<stdio.h>
#include<string.h>
int main()
{
	//freopen("datain.txt","r",stdin);	
	//freopen("dataout.txt","w",stdout);
	int n;
	while(scanf("%d",&n)&&n!=-1)
	{
		printf("Round %d\n",n);
		char in1[1000],in2[1000];
		scanf("%s",in1);//答案 
		scanf("%s",in2);//猜测 
		int len1,len2,wrong=0,win=0;
		
		len1=strlen(in1);
		len2=strlen(in2);//猜测和答案比对 
		for(int i=0;i<len2;i++)
		{
			int flag=1,flag0=1;//记录是否错误,flag0记录是否数组 全为0 
			for(int j=0;j<len1;j++)
			{
				if(in2[i]==in1[j])
				{
					in1[j]='0'; 
					flag=0;
					
				}	 				
			}
			if(flag==1)
			{
					wrong++;
					
			}
			for(int i=0;i<len1;i++)
			{
				if(in1[i]!='0')
				{
					flag0=0;
				} 
				
			}
			if(flag0)
			{
				win=1;
				break;
			}
	
		}
		if(win&&wrong<7)
		{
			printf("You win.\n");
		}
		if(!win&&wrong<7)
		{
			printf("You chickened out.\n");
			
		}
		if(wrong>=7)
		{
			printf("You lose.\n");
		}

	}
	
	
	return 0;
}

例题4-3

问题提出:n个站成一圈逆时针编号,A逆时针数k个人,B顺时针数m个人。数完之后,淘汰掉A、B数的人。然后接着A顺时针m,B逆时针n。直到所有人全部被淘汰。

问题分析:不需要问题转换,直接根据题意进行编程。

解决方案:利用一个长度为n的people数组存储现在人员的状态,0表示淘汰,非0表示还在游戏中。那么用Apos来指示当前A的位置,Bpos来指示B的位置。

题目中逆时针数数,实际上就是对people数字由小到大的正向数数,逆时针就是由大到小的逆向数数,那么顺时针或者逆时针数数大于一圈的时候,需要多Apos和Bpos进行复位。知道people数组全为0.结束。

补充说明:

1、从问题提出可以看出,A逆时针数数和B顺时针数数是重读多次出现,那么,可以将其写成函数。会使得代码更加简洁。

2、书中给出了一个left来记录剩余的人数,相对于判断people数组全为0,更节省时间。

3、注意输出格式。使用%3d更加简洁。这一点之前我并不知道。

时间:2017/6/20

#include<stdio.h>
int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	int n,k,m;
	while(scanf("%d%d%d",&n,&k,&m)==3&&n&&k&&m)
	{
		int people[1000];
		for(int i=0;i<=n;i++)
		{
			people[i]=i;
		}
		int Apos=1,Bpos=n,flag=1;//A、B官员的位置
		int a,b;
		while(flag)
		{
			a=k;
			b=m;
			while(a)
			{
				if(Apos>n)
				{
					Apos=Apos-n;
				}
			
				if (people[Apos++]!=0)
				{
					a--;
				}
		 	
			}
			while(b)
			{
				if(Bpos<1)
				{
					Bpos=Bpos+n;	
				}
				if (people[Bpos--]!=0)
				{
					b--;
				}
			}
		Apos=Apos-1;
		Bpos=Bpos+1;
		
		people[Apos]=0;
		people[Bpos]=0;
		if(Apos==Bpos)
		{
			if(Apos<10)
		{
			printf("  ");
		}
		if(Apos>=10&&Apos<100)
		{
			printf(" ");
		}
			printf("%d",Apos);	
		}
		else
		{
			if(Apos<10)
		{
			printf("  ");
		}
		    if(Apos>=10&&Apos<100)
		{
			printf(" ");
		}
		printf("%d",Apos);
		if(Bpos<10)
		{
			printf("  ");
		}
		if(Bpos>=10&&Bpos<100)
		{
			printf(" ");
		}
		printf("%d",Bpos);
				
		}
		int flag1=0;
		for(int i=1;i<=n;i++)
		{
			if(people[i]!=0)
			{
				flag1=1;
				break;
			}
                
		}
		if(!flag1)
			flag=0;
		else
		{
			flag=1;
			printf(",");
		}
			
	
	}
	printf("\n");
		
		
	}
	
	return 0;
}
例题4-4

问题提出:给定一段字符通过一定规则的编码成二进制串,然后给出二进制串进行解码。

问题分析:本题中包含两个过程,即编码和解码。完成这两个功能就可。

根据编码规则需要建立二进制串和字符的映射。首先我们可以采用key-value这样的表示方法的数据结构(比如C#中的list),但是在这个阶段,没有提供这样的数据结构。那么我们需要对存储做一下转换。我们可以发现,此时的编码和编码长度有关。并且编码长度决定在这个编码长度下能够编码的个数。比如编码长度为1,那么可以编码1个。如果为2,则为3个,如果为i,就为2^i-1。那么我们就可以将编码存储在一个(编码长度,序号)的二维数组中。

解码方面,就是一个字符读入和二维数组匹配过程。

解决方案:

1、通过code[编码长度][序号]存储编码。

2、边读边解码。

补充说明:

1、本题目是字符处理类的题目,其实核心编程思想不难,主要是处理输入输出有些麻烦,所以一定要一步一步的做,不秀技巧,尽量朴实好调试。

2、本题目中解码输入可以换行,导致如果直接用getchar()会接收到回车,如果在主函数中使用多个getchar()去接收回车以抵消无效输出,会导致调试非常麻烦,强烈建议写一个不读取回车的字符读入函数,源代码中自定义getnonchar()函数来完成这个功能。

时间:2017/6/21

#include<stdio.h>
#include<math.h>
#include<string.h>
char getnonchar()
{
	char c;
	c=getchar();
	while(c=='\n'||c=='\r')
	{
		c=getchar();
	}
	return c;
}
int read01(char code[8][256],int ws)
{
	int ed,code01=0;
	char c;
	int a=0;
	ed=pow(2,ws)-1;
	do
	{
	if(a!=0)
	{
		printf("%c",code[ws][code01]);
	}
	code01=0;
	for(int i=0;i<ws;i++)
	{
		c=getnonchar();
		code01=code01+int(c-'0')*pow(2,ws-i-1);	
	}
	a++;
	}while(code01!=ed);	

}


int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	char c;
	char code[8][256]; 
	while ((c=getnonchar())!=EOF&&c)
	{
		//编码 
		memset(code,0,sizeof(code));
		code[1][0]=c;
		int i=1,j=1;
		while((c=getchar())!='\n')
		{
			if (c=='\r')
			{
				c=getchar();
			}
			
			if(j>=pow(2,i)-1)
			{
				i++;
				j=0;
			}
			code[i][j++]=c;
		}
		//解码
		char a1,a2,a3;
		int  ws;
		a1=getnonchar();
		a2=getnonchar();
		a3=getnonchar();
		 while(!(a1=='0'&&a2=='0'&&a3=='0'))
		 {
		 	ws=(a1-'0')*pow(2,2)+(a2-'0')*pow(2,1)+(a3-'0')*pow(2,0);
		 	read01(code,ws);
		 	a1=getnonchar();
			a2=getnonchar();
			a3=getnonchar(); 	
		 }
		 printf("\n");
	}
	
	return 0;
} 

例题4-5

本题目书中进行了详细分析,尤其第二种的思维模式,值得借鉴,非常有用,现贴出第二种思维模式的代码。

时间:2017/6/23

#include<stdio.h>
#include<string.h>
#define maxd 10000
struct Command
{
	char c[5];
	int r1,c1,r2,c2;
	int a,x[20];
}cmd[maxd];
int r,c,n;
int simulate(int* r0,int* c0)
{
	for(int i=0;i<n;i++)
	{
		if(cmd[i].c[0]=='E')
		{
			if(cmd[i].r1==*r0&&cmd[i].c1==*c0)
			{
				*r0=cmd[i].r2;
				*c0=cmd[i].c2;
			}
			else if(cmd[i].r2==*r0&&cmd[i].c2==*c0)
			{
				*r0=cmd[i].r1;
				*c0=cmd[i].c1;
			}
		}
		else
		{
			int dr=0,dc=0;
			for(int j=0;j<cmd[i].a;j++)
			{
				int x=cmd[i].x[j];
				if(cmd[i].c[0]=='I')
				{
					if(cmd[i].c[1]=='R'&&x<=*r0)dr++;
					if(cmd[i].c[1]=='C'&&x<=*c0)dc++;
					
				}
				else
				{
					if(cmd[i].c[1]=='R'&&x==*r0)return 0;
					if(cmd[i].c[1]=='C'&&x==*c0)return 0;
					if(cmd[i].c[1]=='R'&&x<*r0)dr--;
					if(cmd[i].c[1]=='C'&&x<*c0)dc--;
					
				}
				
			}
			*r0+=dr;*c0+=dc;		
		}
	}
	return 1;
}
int main()
{
	int r0,c0,q,kase=0;
	while(scanf("%d%d%d",&r,&c,&n)==3&&r)
	{
		for(int i=0;i<n;i++)
		{
			scanf("%s",cmd[i].c);
			if(cmd[i].c[0]=='E')
			{
				scanf("%d%d%d%d",&cmd[i].r1,&cmd[i].c1,&cmd[i].r2,&cmd[i].c2);
			}
			else
			{
				scanf("%d",&cmd[i].a);
				for(int j=0;j<cmd[i].a;j++)
					scanf("%d",&cmd[i].x[j]);
			}
		}
		if(kase>0)
			printf("\n");
		printf("Spreadsheet #%d\n",++kase);
		
		scanf("%d",&q);
		while(q--)
		{
			scanf("%d%d",&r0,&c0);
			printf("Cell data in (%d,%d) ",r0,c0);
			if(!simulate(&r0,&c0))printf("GONE\n");
			else printf("moved to (%d,%d)\n",r0,c0);
		}
	}
	
	return 0;
}

例题4-6

每个功能写成一个函数。调试的时候,先每个函数进行测试,再总体测试。

#include <stdio.h>
#include <string.h>
char SID[300][15];
int CID[300];
char name[300][15];
int score[300][4];
int cpos=0;
void Showmainmenu()
{
	printf("Welcome to Student Performance Management System (SPMS).\n\n");
	printf("1 - Add\n");
	printf("2 - Remove\n");
	printf("3 - Query\n");
	printf("4 - Show ranking\n");
	printf("5 - Show Statistics\n");
	printf("0 - Exit\n\n");
}
int  QuerySID(char cSID[15])
{
	for(int i=0;i<cpos;i++)
	{
		if(strcmp(cSID,SID[i])==0)
		return 1;
	}
	return 0;
	
}
void Add()
{
    int cCID,csores[4];
    char cSID[15],cname[15];
    printf("Please enter the SID, CID, name and four scores. Enter 0 to finish.\n");
	while(scanf("%s",cSID)&&strcmp(cSID,"0")!=0)
	{
		
		scanf("%d",&cCID);
		scanf("%s",cname);
		for (int i=0;i<4;i++)
		{
			scanf("%d",&csores[i]);
		}
		if(QuerySID(cSID))
		{
			printf("Duplicated SID.\n");
		}
		else
		{
			strcpy(SID[cpos],cSID);
			CID[cpos]=cCID;
			strcpy(name[cpos],cname);
			for (int i=0;i<4;i++)
			{
			score[cpos][i]=csores[i];
			}
			cpos++;	
		}
	printf("Please enter the SID, CID, name and four scores. Enter 0 to finish.\n");		
	
	}	
	
}
void Remove()
{
	printf("Please enter SID or name. Enter 0 to finish.\n");
	
    char cinput[15];
    while(scanf("%s",cinput)&&strcmp(cinput,"0")!=0)
	{
		int amountremoved=0;
		for(int i=0;i<cpos;)
		{
			if(strcmp(cinput,SID[i])==0||strcmp(cinput,name[i])==0)
		 {
		 	strcpy(SID[i],"0");
		 	strcpy(name[i],"0");
		 	for(int j=i;j<cpos-1;j++)
			 {
			 	strcpy(SID[j],SID[j+1]);
			 	strcpy(name[j],name[j+1]);
				CID[j]=CID[j+1];
			for (int m=0;m<4;m++)
				{
					score[j][m]=score[j+1][m];
				}
			 	
			 }
			 cpos--;
			 amountremoved++;
			 i=0;
		 }
		 else
		 {
		 	i++;
		 }
			
		}
		 printf("%d student(s) removed.\n",amountremoved);
		 printf("Please enter SID or name. Enter 0 to finish.\n");
		
	}
	
		
}

void Query()
{
	char cinput[15];
    int totalscore,tmp;
    printf("Please enter SID or name. Enter 0 to finish.\n");
    while(scanf("%s",cinput)&&strcmp(cinput,"0")!=0)
	{
		
		for(int i=0;i<cpos;i++)
		{
			
			 if(strcmp(cinput,SID[i])==0||strcmp(cinput,name[i])==0)
		 	{
		 		
		 		totalscore=score[i][0]+score[i][1]+score[i][2]+score[i][3];
		 		int rank=cpos;
		 		for(int j=0;j<cpos;j++)
				{
					if(totalscore>=score[j][0]+score[j][1]+score[j][2]+score[j][3]&&i!=j)
						rank--;
				}
				    printf("%d ",rank);
				    printf("%s %d %s %d %d %d %d ",SID[i],CID[i],name[i],score[i][0],score[i][1],score[i][2],score[i][3]);
					printf("%d %.2f\n",totalscore,(float(totalscore)+1e-5)/4);
					
						
			}		 		
		}
		printf("Please enter SID or name. Enter 0 to finish.\n");		
	}
		
			
}
void Showranking()
{
	
	printf("Showing the ranklist hurts students' self-esteem. Don't do that.\n");
	
}

void  Showstatistics()
{
	
	printf("Please enter class ID, 0 for the whole statistics.\n");
	int k,pass[4],passp[300][4],passp2[5],totalscore[4];
	memset(pass,0,sizeof(pass));
	memset(passp,0,sizeof(passp));
	memset(totalscore,0,sizeof(totalscore));
	memset(passp2,0,sizeof(passp2));
	scanf("%d",&k);
	if(k!=0)
	{
		int sump=0;
		for(int i=0;i<cpos;i++)
		{
			if(CID[i]==k)
			{
				sump++;
				for(int j=0;j<4;j++)
				{
					totalscore[j]=totalscore[j]+score[i][j];
					if(score[i][j]>=60)
					{
						pass[j]++;
						passp[i][j]++;
						
					}
				}
				
			}	
		}
		
		for(int i=0;i<4;i++)
		{
			if(i==0)
			printf("Chinese\n");
			if(i==1)
			printf("Mathematics\n");
			if(i==2)
			printf("English\n");
			if(i==3)
			printf("Programming\n");
			if(sump==0)
			{
				printf("Average Score: %s\n","-nan");	
			}
			if(sump!=0)
			{
			printf("Average Score: %.2f\n",(double(totalscore[i])+1e-5)/sump);				
			}
			printf("Number of passed students: %d\n",pass[i]);
			printf("Number of failed students: %d\n\n",sump-pass[i]);
		}
			printf("Overall:\n");
			for(int i=0;i<cpos;i++)
			{
				passp2[passp[i][0]+passp[i][1]+passp[i][2]+passp[i][3]]++;
			}
			printf("Number of students who passed all subjects: %d\n",passp2[4]);
			printf("Number of students who passed 3 or more subjects: %d\n",passp2[4]+passp2[3]);
			printf("Number of students who passed 2 or more subjects: %d\n",passp2[4]+passp2[3]+passp2[2]);
		    printf("Number of students who passed 1 or more subjects: %d\n",passp2[4]+passp2[3]+passp2[2]+passp2[1]);
		    printf("Number of students who failed all subjects: %d\n\n",sump-(passp2[4]+passp2[3]+passp2[2]+passp2[1]));
	
	}
	else
	{
		
		int sump=0;
		for(int i=0;i<cpos;i++)
		{
				sump++;
				for(int j=0;j<4;j++)
				{
					totalscore[j]=totalscore[j]+score[i][j];
					if(score[i][j]>=60)
					{
						pass[j]++;
						passp[i][j]++;
						
					}
				}	
		}
		
		for(int i=0;i<4;i++)
		{
			if(i==0)
			printf("Chinese\n");
			if(i==1)
			printf("Mathematics\n");
			if(i==2)
			printf("English\n");
			if(i==3)
			printf("Programming\n");
			if(sump==0)
			{
				printf("Average Score: %s\n","-nan");	
			}
			if(sump!=0)
			{
			printf("Average Score: %.2f\n",(double(totalscore[i])+1e-5)/sump);				
			}
			printf("Number of passed students: %d\n",pass[i]);
			printf("Number of failed students: %d\n\n",sump-pass[i]);
		}
			printf("Overall:\n");
			for(int i=0;i<cpos;i++)
			{
				passp2[passp[i][0]+passp[i][1]+passp[i][2]+passp[i][3]]++;
			}
			printf("Number of students who passed all subjects: %d\n",passp2[4]);
			printf("Number of students who passed 3 or more subjects: %d\n",passp2[4]+passp2[3]);
			printf("Number of students who passed 2 or more subjects: %d\n",passp2[4]+passp2[3]+passp2[2]);
		    printf("Number of students who passed 1 or more subjects: %d\n",passp2[4]+passp2[3]+passp2[2]+passp2[1]);
		    printf("Number of students who failed all subjects: %d\n\n",sump-(passp2[4]+passp2[3]+passp2[2]+passp2[1]));
	
				
		
	}
		
}




int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	int k;
	Showmainmenu();
	while(scanf("%d",&k)&&k)
	{
		switch(k)
		{
			case 1:
			{
				Add();
				Showmainmenu();
				break;				
			}
			case 2:
			{
				Remove();
				Showmainmenu();
				break;
			}
			case 3:
			{
				Query();
				Showmainmenu();	
				break;
			}
			case 4:
			{
				Showranking();
				Showmainmenu();	
				break;
			}
			case 5:
			{
			    Showstatistics();
				Showmainmenu();
				break;
			}
			default:
			{
				break;
			}
		}	
	}	
	return 0;
}

习题4-1(WA,并不知道问题出在什么地方)

本题思路:黑棋的将走法,有5种。分别为:1.初始时,红方的将和黑方的将相对,不能将死;2.黑将向左一步的位置,被红方将死(即红方的棋能够到达那个位置);3.黑将的右边一步。4.黑将的上边一步;5。黑将的下边一步。

那么只要保证这5种走位,都被红方封杀,就能保证将死的状态。

#include<stdio.h>
#define maxp 50
struct pieces
{
	char type;
	int x;
	int y;	
}ps[maxp];
int lenps;
int BGx,BGy,RGx,RGy;
int Gcheck(int x1,int y1,int x2,int y2)
{
	int p=0;//
	for(int i=0;i<lenps;i++) 
	{
		if(ps[i].y==y1&&(ps[i].x>x2&&ps[i].x<x1))
			p++;	
	}
	if(p==0&&y1==y2)
	return 0;
	return 1;
	
}

int Rcheck(int x1,int y1,int x2,int y2)
{
	int a=0,p=0;//横向,纵向有阻挡
	if(x1==x2&&y1==y2)
	return 1;
	for(int i=0;i<lenps;i++) 
	{
		if(ps[i].x==x1&&((ps[i].y>y1&&ps[i].y<y2)||(ps[i].y>y2&&ps[i].y<y1)))
			a++;
		if(ps[i].y==y1&&((ps[i].x>x1&&ps[i].x<x2)||(ps[i].x>x2&&ps[i].x<x1)))
			p++;	
	}
	
	if(p==0&&y1==y2)
	return 0;
	if(a==0&&x1==x2)
	return 0;
	return 1;
	
}

int Ccheck(int x1,int y1,int x2,int y2)
{
	int a=0,p=0;//横向,纵向的棋子个数
	if(x1==x2&&y1==y2)
	return 1;
	for(int i=0;i<lenps;i++) 
	{
		if(ps[i].x==x1&&((ps[i].y>y1&&ps[i].y<y2)||(ps[i].y>y2&&ps[i].y<y1)))
			a++;
		if(ps[i].y==y1&&((ps[i].x>x1&&ps[i].x<x2)||(ps[i].x>x2&&ps[i].x<x1)))
			p++;	
	}
	if(p==1&&y1==y2)
	return 0;
	if(a==1&&x1==x2)
	return 0;	
	return 1;	
}
int Hcheck(int x1,int y1,int x2,int y2)
{
	int up=0,down=0,left=0,right=0;//上,下,左,右是否hobbing  
	if(x1==x2&&y1==y2)
	return 1;
	for(int i=0;i<lenps;i++) 
	{
		if(ps[i].x==x1+1&&ps[i].y==y1)
			up=1;
		if(ps[i].x==x1-1&&ps[i].y==y1)
			down=1;	
		if(ps[i].y==y1-1&&ps[i].x==x1)
			left=1;	
		if(ps[i].y==y1+1&&ps[i].x==x1)
			right=1;			
	}
	
	if(!up)
	{
		if(x2==x1+2&&(y2==y1+1||y2==y1-1))
		return 0;
	}
	if(!down)
	{
		if(x2==x1-2&&(y2==y1+1||y2==y1-1))
		return 0;
	}
	if(!left)
	{
		if(y2==y1-2&&(x2==x1+1||x2==x1-1))
		return 0;
	}
	if(!right)
	{
		if(y2==y1+2&&(x2==x1+1||x2==x1-1))
		return 0;
	}
	return 1;		
}
int canArrive(int x,int y)
{
	int Gc=1,Rc=1,Hc=1,Cc=1;
	for(int i=0;i<lenps;i++)
	{
		if(ps[i].type=='G')
		{
			Gc=Gcheck(ps[i].x,ps[i].y,x,y);
			if (Gc==0)
			return 0;
		}
		if(ps[i].type=='R')
		{
			Rc=Rcheck(ps[i].x,ps[i].y,x,y);
			if (Rc==0)
			return 0;	
		}
		if(ps[i].type=='H')
		{
			Hc=Hcheck(ps[i].x,ps[i].y,x,y);
			if (Hc==0)
			return 0;
		}
		if(ps[i].type=='C')
		{
			Cc=Ccheck(ps[i].x,ps[i].y,x,y);	
			if (Cc==0)
			return 0;
		}
		
	}
	return 1;
	
}
int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	int up,down,left,right;
	char tmp;
	while(scanf("%d",&lenps)&&lenps)
	{	
                int flag=0;
		scanf("%d%d",&BGx,&BGy);
		for(int i=0;i<lenps;i++)
		{
			scanf("%c",&tmp);
			scanf("%c",&ps[i].type);
			scanf("%d%d",&ps[i].x,&ps[i].y);
			if(ps[i].type=='G')
			{
				RGx=ps[i].x;
				RGy=ps[i].y;
			}
		}
		
		int p=0;
		for(int i=0;i<lenps;i++) 
		{	
			if(ps[i].y==RGy&&ps[i].x>BGx&&ps[i].x<RGx)
			p++;	
		}
		if(p==0&&RGy==BGy)
			flag=1;	
			
		if(BGx>1)
		{
			down=canArrive(BGx-1,BGy);
		}
		else
		{
			down=0;//1说明不能将死,0说明能够将死 
		}
		if(BGx<3)
		{
			up=canArrive(BGx+1,BGy);
		}
		else
		{
			up=0;
		}
		if(BGy>4)
		{
			left=canArrive(BGx,BGy-1);
		}
		else
		{
			left=0;
		}
		if(BGy<6)
		{
			right=canArrive(BGx,BGy+1);
		}
		else
		{
			right=0;
		}
		if(!up&&!down&&!right&&!left&&!flag)
		{
			printf("YES\n");
		}
		else
		{
			printf("NO\n");
		}
			
	}
	

return 0;	
}

习题4-2

本题思路:根据输出形式,可以先确定大小,再一个点一个点的搜索,来确定满足条件的正方形个数。再改变大小,进行搜索。

#include<stdio.h>
#include<string.h>
#define maxn 1000
int Hori[maxn];
int Vert[maxn];
int Findsquare(int n,int sp,int size)
{
	
	for(int i=0;i<size;i++)
	{
		if (!(Hori[sp+i]))
			return 0;
		if (!(Vert[sp+n*i]))
			return 0;
		if (!(Hori[sp+size*n+i]))
			return 0;
		if (!(Vert[sp+size+n*i]))
			return 0;	
		
	}
	return 1;		
}



int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	int m,n,rnd=1;
	while(scanf("%d",&n)!=EOF&&n)
	{
		if(rnd!=1)
		{
			printf("\n");
			for(int i=0;i<34;i++)
			{
				printf("*");
			}
		printf("\n\n");
		
		}
		
		int results[maxn],flag=1;
		printf("Problem #%d\n\n",rnd++);
	    memset(results,0,sizeof(results));
		memset(Hori,0,sizeof(Hori));
		memset(Vert,0,sizeof(Vert));
		scanf("%d",&m);	
		while(m--)
		{
			char tmp;
			int i,j,index;
			scanf("%c",&tmp);//接收回车 
			scanf("%c",&tmp);
			scanf("%d",&i);
			scanf("%d",&j);
			
			if(tmp=='H')
			{
				index=(i-1)*n+j;
				Hori[index]=1;
			}
			if(tmp=='V')
			{
				index=(j-1)*n+i;
				Vert[index]=1;
			}
		}
		for(int i=1;i<n;i++)//正方形大小 
		{
			for(int j=1;j<n*(n-1);j++)//搜索起点 
			{
				int CB;
				CB=Findsquare(n,j,i);
				if(CB)
				{
					results[i]++;		
				}
				
			}
		}
		for(int i=1;i<n;i++)
		{
			if(results[i])
			{
				
				printf("%d square (s) of size %d\n",results[i],i);
				flag=0;		
			}
		}
		if(flag)
		{
			printf("No completed squares can be found.\n");
		}
		
	}
	
	return 0;
} 

习题4-3

习题4-4

本题思路:模拟骰子的x、y、z轴旋转,穷举出所有情况,然后和初始的骰子进行匹配,看是否一样。本题应该有更加简单的搜索方法,还需要从后面章节进行学习。

#include<stdio.h>
#include<string.h>
int isequal(char cube1[7],char cube2[7])
{
	int flag=1;
	for (int i=1;i<7;i++)
	{
		if(cube1[i]!=cube2[i])
			flag=0;
	}
	if(flag)
	{
		return 1;
	}
	
	else
	{
		return 0;
	}
	
}

int horirotation(char *cube2)
{
	char tmp;
	tmp=cube2[2];
	cube2[2]=cube2[4];
	cube2[4]=cube2[5];
	cube2[5]=cube2[3];
	cube2[3]=tmp;
	
}
int verirotation(char *cube2)
{
	char tmp;
	tmp=cube2[2];
	cube2[2]=cube2[1];
	cube2[1]=cube2[5];
	cube2[5]=cube2[6];
	cube2[6]=tmp;	
}

int lrrotation(char *cube2)
{
	char tmp;
	tmp=cube2[1];
	cube2[1]=cube2[4];
	cube2[4]=cube2[6];
	cube2[6]=cube2[3];
	cube2[3]=tmp;	
	
}

int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	char cube1[7],cube2[7],cube3[7],cube4[7];
	char m;
	
	while(scanf("%c",&m)!=EOF)
	{
		cube1[1]=m;
		int flag=0;
		for(int i=2;i<7;i++)
		{
			scanf("%c",&m);
			cube1[i]=m;	
		}
		for(int i=1;i<7;i++)
		{
			scanf("%c",&m);
			cube2[i]=m;	
			cube3[i]=m;
		}
		//判断是否相同 
		
		int hori=4,veri=4,lr=4;
		while(veri--)
		{
			while(hori--)
			{
				for(int i=1;i<7;i++)
				{
					cube4[i]=cube3[i];//保存水平状态 
				}
				while(lr--)
				{	
					lrrotation(cube3);
					if(isequal(cube1,cube3))
					{	
						flag=1;	
					}	
				}				
				for(int i=1;i<7;i++)
				{
					cube3[i]=cube4[i];
				}
				horirotation(cube3);
				if(isequal(cube1,cube3))
				{
					flag=1;	
				}
				lr=4;	
				
			}
			for(int i=1;i<7;i++)
			{
				cube3[i]=cube2[i];
			}
			verirotation(cube3);
			if(isequal(cube1,cube3))
			{
				flag=1;	
			}
			for(int i=1;i<7;i++)
			{
				cube2[i]=cube3[i];//保存垂直状态 
			}
			hori=4;
		}
	
	if(flag)
	{
		printf("TRUE\n");
		
	}
	else
	{
		printf("FALSE\n");
	}
			
	scanf("%c",&m);	
	}
	
	
} 

习题4-8

本题思路:通过模拟每个时刻的状态,来判断。本程序模拟1000次,在1000次中寻找全醒的时刻,如果有,则输出,没有则输出-1。

#include<stdio.h>
#define N 100
 typedef struct 
{
	int wk[20];
	int lenthwk; 
	int p;
}Stu;
int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	int m,rnd=1;
	while(scanf("%d",&m)&&m)
	{
		Stu stu[N];
		int find=0;
		for(int i=1;i<=m;i++)
		{
			int wake=0,sleep=0,ini=1;
			scanf("%d",&wake);
			for(int j=0;j<wake;j++)
			{
				stu[i].wk[j]=0;
			}
			scanf("%d",&sleep);
			for(int j=wake;j<sleep+wake;j++)
			{
				if(wake>0&&j==wake)
				{
					stu[i].wk[wake]=2;
				}
				else
				{
					stu[i].wk[j]=1;	
				}	
			}
			scanf("%d",&ini);
			stu[i].p=ini-1;
			stu[i].lenthwk=wake+sleep;		
		}
		int amslee=0,amwake=0;
		for(int i=1;i<=m;i++)
		{
			if(stu[i].wk[stu[i].p]==2||stu[i].wk[stu[i].p]==1)
			   	amslee++;
			else
				amwake++;	
		}		
		for(int i=1;i<=500;i++)
		{
			if(amwake==m)
			{
				find=i;
				break;
			}
			else
			{
				for(int j=1;j<=m;j++)
				{
					int tmp=(stu[j].p+1)%(stu[j].lenthwk);
					if(stu[j].wk[tmp]!=2)
					{
						stu[j].p=tmp;
					}
					else
					{
						if(amslee>amwake)
						{
							stu[j].p=tmp;	
						}
						else
						{
							stu[j].p=0;
						}
	
					}
				
				}	
			}
			amslee=0;amwake=0;
			for(int i=1;i<=m;i++)
			{
			if(stu[i].wk[stu[i].p]==2||stu[i].wk[stu[i].p]==1)
			   	amslee++;
			else
				amwake++;
			}				
		} 
		if(find)
			printf("Case %d: %d\n",rnd++,find);
		else
			printf("Case %d: -1\n", rnd++);
	
	}

	return 0;
} 

习题4-10

本题思路:首先将水的立方数换算为高度,将每个格子的高度进行排序,再一个一个填满,填满的时候,高度逐步减少,直至为0或者为负数的时候停止。因为换算高度的时候要除以100。所以会出现float和double类型不准的情况,这个时候就可以使用书中p95的方法,加上一个很小的数EPS,来校准精度。

#include<stdio.h>
#include<algorithm>
#define EPS 1e-4
using namespace std;
float dw(float water,int a,int amount) {
	return water-a*amount;
}
int main() {
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	int m,n,rnd=1;
	while(scanf("%d",&m)&&m) {
		int reg[1000],index=-1;
		double water,watertmp,wl,per;
		scanf("%d",&n);
		for(int i=0; i<m*n; i++) {
			scanf("%d",&reg[i]);
		}
		scanf("%lf",&water);
		water=water/100.00;
		watertmp=water;
		sort(reg,reg+m*n);
		for(int i=0; i<m*n-1; i++) {

			int a=reg[i+1]-reg[i];
			water=dw(water,a,i+1);
			if(water>0) 
			{
				watertmp=water;
			} 
			else 
			{
				index=i;
				break;
			}
		}
		if(index==-1) {
			index=m*n-1;
		}
		wl=watertmp/(index+1);
		per=double((index+1)*100)/(m*n);
		printf("Region %d\n",rnd++);
		printf("Water level is %.2lf meters.\n",wl+reg[index]+EPS);
		printf("%.2lf percent of the region is under water.\n\n",per+EPS);



	}




	return 0;
}





  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值