例题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
#include
#include
//#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
例题4-2
问题提出:已知答案和猜测两个字符数组,通过比对猜测数组和答案数组中的字符,判断是否猜对?
问题分析:如果要猜测对,需要满足:
1.猜测数组中有答案数组中的全部字符。
2.猜测数组中在猜对最后一个字符之前,错误的字符小于7.
那么猜测错,必须满足
1.猜测数组在猜对最后一个字符之前,错误字符大于7。
那么没有猜测对,也没有猜测错。就为待定状态
解决方案:两个角度
1.用答案数组比对猜测数组
2.用猜测数组比对答案数组。
本编码采用角度2.
补充说明:1、本题和猜测数组的顺序有关系,不能像习题4-1那样可以先统计再判断。
2、UVA的debug数据有问题。不适合测试
时间2014/6/20
#include
#include
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=7)
{
printf("You lose.\n");
}
}
return 0;
}
问题提出: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
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
#include
#include
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=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
#include
#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;i0)
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
#include
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=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=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=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
习题4-1(WA,并不知道问题出在什么地方)
本题思路:黑棋的将走法,有5种。分别为:1.初始时,红方的将和黑方的将相对,不能将死;2.黑将向左一步的位置,被红方将死(即红方的棋能够到达那个位置);3.黑将的右边一步。4.黑将的上边一步;5。黑将的下边一步。
那么只要保证这5种走位,都被红方封杀,就能保证将死的状态。
#include
#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;ix2&&ps[i].xy1&&ps[i].yy2&&ps[i].yx1&&ps[i].xx2&&ps[i].xy1&&ps[i].yy2&&ps[i].yx1&&ps[i].xx2&&ps[i].xBGx&&ps[i].x1)
{
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
#include
#define maxn 1000
int Hori[maxn];
int Vert[maxn];
int Findsquare(int n,int sp,int size)
{
for(int i=0;i
习题4-3
习题4-4
本题思路:模拟骰子的x、y、z轴旋转,穷举出所有情况,然后和初始的骰子进行匹配,看是否一样。本题应该有更加简单的搜索方法,还需要从后面章节进行学习。
#include
#include
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
#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;j0&&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
#include
#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; i0)
{
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;
}