例题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",®[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; }