写这个的原因是看到一位大神的习题答案总结,于是自己心血来潮也想写一个这个,目的主要是督促自己刷题吧,毕竟自己太弱了。
习题3-1 得分 UVa 1585
大致就是设置一个变量记录到当前为止的连续的O的数量,碰到X就变0,水题。
#include<stdio.h>
#include<ctype.h>
#include<string.h>
char s[90];
int main(void)
{
int length,n,sum,num;
scanf("%d",&n);
while(n--)
{
sum=num=0;
scanf("%s",s);
length=strlen(s);
for(int i=0;i<length;i++)
{
if(s[i]=='X')
{
num=0;
continue;
}
num++;
sum+=num;
}
printf("%d\n",sum);
}
return 0;
}
习题3-2 分子量 UV1586
很简单的一个字符串处理。我这里用到了ctype.h里的isupper()函数,还要注意单独一个元素符号后面没有数字的情况。
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#define tan 12.01
#define qing 1.008
#define yang 16.00
#define dan 14.01
char s[90];
int main(void)
{
int i,length,n,temp;
double sum;
scanf("%d",&n);
while(n--)
{
sum=0;
scanf("%s",s);
length=strlen(s);
if(isupper(s[length-1]))
{
s[length]='1';
s[length+1]='\0';
}
length=strlen(s);
for(i=0;i<length-1;i++)
{
if(isupper(s[i]) &&isupper(s[i+1]))
{
switch(s[i])
{
case 'C':sum+=tan;
break;
case 'H':sum+=qing;
break;
case 'O':sum+=yang;
break;
case 'N':sum+=dan;
break;
}
}
if(isupper(s[i]) &&!(isupper(s[i+1])))
{
int j=i+1;
while(!(isupper(s[j]))&&(j<length))
j++;
int myk,weishu=1;
temp=0;
for(myk=j-1;myk>=i+1;myk--)
{
temp+=weishu*(s[myk]-'0');
weishu*=10;
}
switch(s[i])
{
case 'C':sum+=tan*temp;
break;
case 'H':sum+=qing*temp;
break;
case 'O':sum+=yang*temp;
break;
case 'N':sum+=dan*temp;
break;
}
}
}
printf("%.3lf\n",sum);
}
return 0;
}
习题3-3 数数字 UVa1225
水题,数据不大,搞个数组就ok。注意数字字符到int类型的转换。
#include<stdio.h>
#include<ctype.h>
#include<string.h>
char a[40000];
char temp[10];
int main(void)
{
int t,i,n;
int num[10];
scanf("%d",&t);
while(t--)
{
a[0]='\0';
scanf("%d",&n);
for( i=1;i<=n;i++)
{
sprintf(temp,"%d",i);
strcat(a,temp);
}
int length;
length=strlen(a);
for(i=0;i<10;i++)
num[i]=0;
for(i=0;i<length;i++)
num[(a[i]-'0')]++;
for(i=0;i<9;i++)
printf("%d ",num[i]);
printf("%d",num[9]);
printf("\n");
}
return 0;
}
习题3-4 周期串 UVa455
数据量不大,直接暴力枚举周期,用总长度是周期的倍数剔除一部分,然后遍历全串,用%映射到周期中进行比较。
#include<stdio.h>
#include<ctype.h>
#include<string.h>
char a[90];
int main(void)
{
int n;
scanf("%d",&n);
while(n--)
{
scanf("%s",a);
int length;
length=strlen(a);
int i,j,status;
for(i=0;i<length;i++)
{
status=1;
if(length%(i+1)!=0)
continue;
for(j=0;j<length;j++)
{
if(a[j]!=a[j%(i+1)])
status=0;
}
if(status==1)
{
if(n==0)
printf("%d\n",i+1);
else printf("%d\n\n",i+1);
break;
}
}
}
return 0;
}
习题3-5 谜题 UVa227
非常烦的模拟,记得做了好久,注意边界处理和读入(用字符串读比较好,字符格式读入会读入回车符导致意想不到的错误)
#include<stdio.h>
#include<ctype.h>
#include<string.h>
char a[10][10];
int cnt=0;
bool panduan(int i,int j)
{
if((i>=0)&&(i<5)&&(j>=0)&&(j<5))
return true;
else return false;
}
void shuchu(void)
{
int k,m;
printf("\n");
for(k=0;k<5;k++)
{
for(m=0;m<5;m++)
{
printf("%c",a[k][m]);
}
printf("\n");
}
printf("\n");
}
int main(void)
{
char temp,temp1,temp2;
int i,j,status,temp_x,temp_y,num=1;
while((temp=getchar())&&(temp!='Z'))
{
if(temp=='\n')
continue;
a[0][0]=temp;
if(temp==' ')
temp_x=temp_y=0;
for(i=0;i<5;i++)
for(j=0;j<=5;j++)
{
if((i==0)&&(j==0))
continue;
temp2=getchar();
if(temp2=='\n')
continue;
a[i][j]=temp2;
if(temp2==' ')
{
temp_x=i;
temp_y=j;
}
}
status=1;
//printf("\nNow temp_x=%d and temp_y=%d\n",temp_x,temp_y);
while((temp1=getchar()) &&(temp1!='0'))
{
switch(temp1)
{
case 'A':
if(temp_x<=0)
status=0;
else
{
a[temp_x][temp_y]=a[temp_x-1][temp_y];
a[--temp_x][temp_y]=' ';
}
//shuchu();
break;
case 'B':
if(temp_x>=4)
status=0;
else
{
a[temp_x][temp_y]=a[temp_x+1][temp_y];
a[++temp_x][temp_y]=' ';
}
//shuchu();
break;
case 'L':
if(temp_y<=0)
status=0;
else
{
a[temp_x][temp_y]=a[temp_x][temp_y-1];
a[temp_x][--temp_y]=' ';
}
//shuchu();
break;
case 'R':
if(temp_y>=4)
status=0;
else
{
a[temp_x][temp_y]=a[temp_x][temp_y+1];
a[temp_x][++temp_y]=' ';
}
//shuchu();
break;
case '\n':
break;
default:status=0;
break;
}
//printf("Now the step is %c and status=%d\n",temp1,status);
}
if(cnt++)
printf("\n");
printf("Puzzle #%d:\n",num++);
if(status==0)
printf("This puzzle has no final configuration.\n");
else
{
for(i=0;i<5;i++)
{
for(j=0;j<4;j++)
{
printf("%c ",a[i][j]);
}
printf("%c",a[i][4]);
printf("\n");
}
}
}
return 0;
}
习题3-6 纵横字谜的答案 UVa232
又是一道模拟。模拟可难可不难,关键是静下心来做。
首先是输入输出格式,一般一道题目简单了就会在这种地方设卡。这道题的换行要求比较严格,不能有多的换行。解决方法很简单,就是每次输出前输出换行,忽略第一次就好了。
然后是我的算法的一个bug,非常难发现,是一个越界错误,是for循环导致的。所以在以后for的循环变量要运用的时候一定要小心!最后找了一个正确程序,写了批处理对拍才AC。
对拍、生成数据可以看这个博客:
我的算法很智障,就是找到单词的出发点,结束点。
#include<stdio.h>
#include<string.h>
int r,c;
char a[12][12];
char temp_input[13];
int b[12][12];//to record the number of each white grid(0 when black)
int iseligible(int x,int y)
{
if(a[x][y]=='*')
return 0;
if((x==1)||(y==1))
return 1;
if((a[x][y-1]=='*')||(a[x-1][y]=='*'))
return 1;
else
return 0;
}
void fuzhi(void)
{
int temp=0;
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
if(iseligible(i,j))
{
temp++;
b[i][j]=temp;
}
}
}
void row(void)
{
int start_position,end_position;
printf("Across\n");
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
start_position=j;
if(!iseligible(i,j))
continue;
if((j!=1)&&(a[i][j-1]!='*'))
continue;
for(end_position=start_position;end_position<=c;end_position++)
{
if(a[i][end_position]=='*')
{
end_position--;
break;
}
}
if(end_position>c)
end_position=c;
printf("%3d.",b[i][start_position]);
for(int k=start_position;k<=end_position;k++)
printf("%c",a[i][k]);
printf("\n");
}
}
void column(void)
{
int start_position,end_position;
printf("Down\n");
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
start_position=i;
if(!iseligible(i,j))
continue;
if((i!=1)&&(a[i-1][j]!='*'))
continue;
for(end_position=start_position;end_position<=r;end_position++)
{
if(a[end_position][j]=='*')
{
end_position--;
break;
}
}
if(end_position>r)
end_position=r;
printf("%3d.",b[start_position][j]);
for(int k=start_position;k<=end_position;k++)
printf("%c",a[k][j]);
printf("\n");
}
}
int main(void)
{
//freopen("in.txt","r",stdin);
//freopen("outwrong.txt","w",stdout);
int num_puzzle=0;
while(scanf("%d",&r)&&(r!=0))
{
if(num_puzzle)
printf("\n");
memset(b,0,sizeof(0));
scanf("%d",&c);
num_puzzle++;
for(int i=1;i<=r;i++)
{
scanf("%s",temp_input);
for(int j=1;j<=c;j++)
a[i][j]=temp_input[j-1];
}
fuzhi();//to allowcate different numbers of each eligible white grid
printf("puzzle #%d:\n",num_puzzle);
row();//to print the across words
column();
}
return 0;
}
习题3-7 DNA序列 UVa1368
这道题很有意思,一开始我都没想到做法。其实很简单:题目要求是Hamming距离和最小,又因为每个字符串都是由固定的TAGC组成的,所以我们可以统计每一位出现的次数,出现次数最多的就是这一位的字母。另外要注意出现次数相同时,按照题目要求,字典序排列。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[1010][5],b[1010];//a stands for the frequency each alphabet occurs in each position,b stands for the answer string
//a b starts from 1
int n,m,ans;
char temp[1010];
int chartonum(char x)
{
switch (x)
{
case 'A':return 1;
case 'C':return 2;
case 'G':return 3;
case 'T':return 4;
}
}
char numtochar(int x)
{
switch (x)
{
case 1:return 'A';
case 2:return 'C';
case 3:return 'G';
case 4:return 'T';
}
}
void duru(void)
{
int temp_num;
scanf("%s",temp);
for(int i=0;i<n;i++)
{
temp_num=chartonum(temp[i]);
a[i+1][temp_num]++;
}
}
void bijiao(int x)
{
int temp_zuida=a[x][1];
int index_zuida=1;
for(int i=2;i<=4;i++)
{
if(a[x][i]>temp_zuida)
{
temp_zuida=a[x][i];
index_zuida=i;
}
}
ans+=a[x][1]+a[x][2]+a[x][3]+a[x][4]-a[x][index_zuida];
b[x]=index_zuida;
}
int main(void)
{
int casenum;
scanf("%d",&casenum);
while(casenum--)
{
memset(a,0,sizeof(a));
ans=0;
scanf("%d%d",&m,&n);
for(int i=0;i<m;i++)
duru();
for(int i=1;i<=n;i++)
{
bijiao(i);
}
for(int i=1;i<=n;i++)
{
printf("%c",numtochar(b[i]));
}
printf("\n%d\n",ans);
}
return 0;
}
习题3-8 循环小数 Uva202
这题可以说做的我心力交瘁,但是理清思路之后其实不难。这道题做的真的是很吃力,一开始没有思路,看了别人的博客开始瞎几把乱写,最后终于没有做出来。
于是全部推翻重来,终于AC了。
首先是除法的基本原理:保存a/b然后a=a%b*10,不停重复直到出现循环节。
如何判断出现循环节呢?
思路是存储一个status数组,存放每次a%b出现的位置,赋初值为-1。注意算整数求出来的a%b也要存!存成status【a%b】=0;然后每次运算检查status【a%b】是否已经有值了。假如status【a%b】已经等于k,现在是第m位,则第k+1位到第m位是循环节。
#include<iostream>
#include<cstring>
#include<climits>
#include<cmath>
#include<algorithm>
using namespace std;
int xs[10000];
int main(void)
{
int aa,k,m,temp,a,b,zs,num_repeat,index_repeat;
int status[3010];
while(cin>>a>>b)
{
aa=a;
zs=a/b;
memset(status,-1,sizeof(status));
status[a%b]=0;
a=a%b*10;
for(int i=1;i<3010;i++)
{
xs[i]=a/b;
temp=a%b;
if(status[temp]==-1)
{
status[temp]=i;
a=a%b*10;
}
else
{
k=status[temp];
m=i;
break;
}
}
//printf("m=%d and k=%d\n",m,k);
if(m-k>50)
{
printf("%d/%d = %d.",aa,b,zs);
for(int i=1;i<=k;i++)
printf("%d",xs[i]);
printf("(");
for(int i=k+1;i<=k+50;i++)
printf("%d",xs[i]);
printf("...)\n");
}
else
{
printf("%d/%d = %d.",aa,b,zs);
for(int i=1;i<=k;i++)
printf("%d",xs[i]);
printf("(");
for(int i=k+1;i<=m;i++)
printf("%d",xs[i]);
printf(")\n");
}
printf(" %d = number of digits in repeating cycle\n\n",m-k);
}
return 0;
}
习题3-9 子序列 UVa10340
这是一道非常简单的字符串匹配题目,然而因为我太菜,看了题解才会做。
仔细说一下算法:
假设要查找的子串为“ab”。则第一步,在长串中寻找a的位置(第一次出现);第二步,从这个位置往后,搜索b的位置。搜索到b则ab是该长串的子串,反之则不是。
当子串更长时,同样的,子串从左到右每个位置都搜索一遍,关键是“从这个位置往后”。
为什么呢?
首先,这个算法保证了子串里每个字符都在长串里出现了,其次,它保证了这些字符出现的顺序是正确的:假设在子串中b在a后面,因为我们搜索的是长串中第一个出现的a的位置,所以在这以后搜索到的b(如果搜的到)肯定是在至少一个a后面的。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
char s[100000+10],t[100000+10];
int main(void)
{
int flag,length_s,length_t;
while(scanf("%s%s",s,t)!=EOF)
{
length_s=strlen(s);
length_t=strlen(t);
flag=0;
for(int i=0;i<length_t;i++)
{
if(t[i]==s[flag])
{
flag++;
}
}
if(flag==length_s)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
习题3-10 盒子 UVa1587
注意多组数据。这道题我写烦了,基本思路就是判断是不是满足盒子的条件:4*3条边(边可以相等)
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
struct myk{
int chang;
int kuan;};
myk a[10];
bool cmp1(myk x,myk y)//以长优先排序
{
if(x.chang!=y.chang)
return(x.chang<y.chang);
else
return(x.kuan<y.kuan);
}
int main(void)
{
int ans,num;
int b[20];
while(1)
{
ans=1;
for(int i=1;i<=6;i++)
if(scanf("%d%d",&a[i].chang,&a[i].kuan)==EOF)
goto myk;
num=0;
for(int i=1;i<=6;i++)
{
if(a[i].chang<a[i].kuan)
swap(a[i].chang,a[i].kuan);
}
sort(a+1,a+7,cmp1);
/* for(int i=1;i<=6;i++) printf("%d %d\n",a[i].chang,a[i].kuan); */
for(int i=1;i<=3;i++)
{
if((a[2*i-1].chang!=a[2*i].chang)||(a[2*i-1].kuan!=a[2*i].kuan))
ans=0;
}
for(int i=1;i<=3;i++)
{
b[num++]=a[2*i].chang;
b[num++]=a[i*2].kuan;
}
sort(b,b+6);
if((b[0]!=b[1])||(b[2]!=b[3])||(b[4]!=b[5]))
ans=0;
//printf("ans=%d\n",ans);
if(ans)
printf("POSSIBLE\n");
else
printf("IMPOSSIBLE\n");
}
myk:return 0;
}
习题3-11换抵挡装置 UVa1588
题目有点难理解,其实可以把它理解成有n1,n2根棍子,棍子可以互相碰到一起,但是高度不能超过3,有点像高中的木块摩擦问题。就是两个木块相互滑动。其实在脑子里想一想这个模型,就可以避免一个常犯错误,就是小木块往左移动。小木块往左移动可以等效为大木块向右移动。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<limits.h>
#include<math.h>
#include<algorithm>
using namespace std;
int a[300],b[300];
char aa[210],bb[210];
int main(void)
{
//freopen("in.txt","r",stdin);
//freopen("out2.txt","w",stdout);
int ans,ans1,ans2,length_a,length_b,index_a,index_b,status=1;
while(scanf("%s%s",aa,bb)!=EOF)
{
status=1;
ans1=ans2=INT_MAX;
length_a=strlen(aa);
length_b=strlen(bb);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<length_a;i++)
a[i]=aa[i]-'0';
for(int i=0;i<length_b;i++)
b[i]=bb[i]-'0';
for(int i=0;i<=length_a;i++)
{
status=1;
for(index_a=i,index_b=0;index_b<100;index_a++,index_b++)
{
if(a[index_a]+b[index_b]>3)
{
status=0;
break;
}
}
if(status==1)
{
ans1=max(length_a,i+length_b);
break;
}
}
for(int i=0;i<=length_b;i++)
{
status=1;
for(index_b=i,index_a=0;index_a<100;index_a++,index_b++)
if(a[index_a]+b[index_b]>3)
{
status=0;
break;
}
if(status==1)
{
ans2=max(i+length_a,length_b);
//printf("Now ans2=%d and i=%d\n",ans2,i);
break;
}
}
ans=m
in(ans1,ans2);
cout<<ans<<endl;
}
return 0;
}
习题3-12 浮点数 UVa11809
这道题看了题解,羞愧。。。做法是取对数,最后的精度要注意,太大太小都不行,我用的1e-4.
题解百度题号,第一篇我觉得写得非常好,我就不重复了。说一说我从这道题里学到的东西:
第一,查表法的运用。本题的答案是有范围的,可以考虑查表。
第二,部分数学公式的熟练运用,如pow,fabs,log等等。
第三,数学方法的运用:等式两边太大而且有指数则开方。
第四,改程序,写程序一定要谨慎,耐下性子,慎重
#include<iostream>
#include<string.h>
#include<limits.h>
#include<float.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct myk{
double aa;
int bb;};
myk chabiao[10][31];
char input[30];
int main(void)
{
int i,j;
long double m,e,t,a,b,ans;
for(int i=0;i<10;i++)
for(int j=1;j<=30;j++)
{
m=1-pow(2.0,-i-1);
e=pow(2,j)-1;
t=log10(m)+(log10(2)*e);
chabiao[i][j].bb=(int)t;
double temp=t-chabiao[i][j].bb;
chabiao[i][j].aa=pow(10,temp);
//printf("chabiao[%d][%d]:%d %d\n",i,j,chabiao[i][j].aa,chabiao[i][j].bb);
}
while(scanf("%s",input))
{
a=b=0.0;
if((input[0]=='0')&&(input[1]=='e')&&(input[2]=='0'))
break;
a+=input[0]-'0';
for(int i=2;i<=16;i++)
{
a+=(input[i]-'0')*pow(10,1-i);
}
for(int i=18;i<strlen(input);i++)
{
b+=pow(10,strlen(input)-i-1)*(input[i]-'0');
}
//cout<<"a="<<a<<endl<<"b="<<b<<endl;
for(int i=0;i<10;i++)
for(int j=1;j<=30;j++)
{
if((fabs(chabiao[i][j].aa-a)<1e-4)&&(chabiao[i][j].bb==b))
{
printf("%d %d\n",i,j);
//goto jies
hu;
}
}
}
return 0;
}
至此,第三章的习题就完成了,大约做了半个月。希望第四章能在5天内完成。