演算法競賽入門經典(第2版)-劉汝佳-第三章解題原始碼(C語言)
習題3-1
#include<stdio.h>
#include<string.h>
int main(){
int lenth,n;
char s[100];
scanf("%d",&n);
while(n--){
scanf("%s",s);
lenth=strlen(s);
int score=0;
int currento=0;
for(int i=0;i<lenth;i++)
if (s[i]=='O'){
currento++;
score+=currento;
}
else
currento=0;
printf("%d\n",score);
}
return 0;
}
習題3-2
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
int main(){
int n;
scanf("%d",&n);
while(n--)
{
char s[50],ds[50];
double sum=0,tmp=0;
scanf("%s",s);
int lenth = strlen(s);
for(int i=0;i<lenth;){
switch(s[i]){
case 'C':
tmp=12.01;
break;
case 'H':
tmp=1.008;
break;
case 'O':
tmp=16.00;
break;
case 'N':
tmp=14.01;
break;
}
int j=i+1,k=0,l=0,cd=0;
if(isdigit(s[j])){
while (isdigit(s[j])){
ds[k++]=s[j++];
}
for(int m=1;m<=k;m++){
cd+=int(ds[k-m]-'0')*pow(10,l++);
}
sum+=cd*tmp;
i=i+k+1;
}
else
{
sum+=tmp;
i++;
}
}
printf("%.3f\n",sum);
}
return 0;
}
習題3-3
#include<stdio.h>
#include<string.h>
int main()
{
int n,m,ans[10];
scanf("%d",&n);
while(n--)
{
memset(ans,0,sizeof(ans));
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x=i,y;
while(x){
y=x%10;
ans[y]++;
x=x/10;
}
}
for(int i=0;i<9;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[9]);
}
return 0;
}
習題3-4
本題目一定要注意輸出格式。
#include<stdio.h>
#include<string.h>
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
char s[100];
scanf("%s",s);
int lenth=strlen(s);
int i=1;
for (i=1;i<=lenth;i++)
{
int flag=1;
if(lenth%i==0){
char substring[100];
for(int j=0;j<i;j++)
substring[j]=s[j];
for(int m=0;m<lenth;m++)
if(substring[m%i]!=s[m])
{
flag=0;
m=lenth+1;
}
}
else
flag=0;
if(flag)
{
printf("%d\n",i);
i=lenth+1;
if(n) printf("\n");//輸出格式注意
}
}
}
return 0;
}
習題3-5
注意空格和回車的輸入,輸出格式也要注意,演算法本身並不困難。
#include<stdio.h>
#include<string.h>
int main()
{
char puzzle[5][5],c,ins[100];
int puzzlei=1;//失敗為假。
while((c=getchar())!='Z'){
int fail=0;
int x,y;//記錄空白格的位置。
if(puzzlei!=1)
{
printf("\n");//輸出格式控制
}
printf("Puzzle #%d:\n",puzzlei++);
puzzle[0][0]=c;
if(c==' ')
{ x=0;
y=0;
}
int i=0,j=1,n=5;
while(n)
{
if((c=getchar())!='\n')
{
puzzle[i][j]=c;
if(puzzle[i][j]==' ')
{
x=i;
y=j;
}
j++;
}
else
{
i=i+1;
j=0;
n--;
}
}
while((c=getchar())!='0')
{
switch(c)
{
case 'A':
{
if(x-1>=0)
{
puzzle[x][y]=puzzle[x-1][y];
puzzle[x-1][y]=' ';
x=x-1;
}
else
fail=1;
break;
}
case 'B':
{
if(x+1<5)
{
puzzle[x][y]=puzzle[x+1][y];
puzzle[x+1][y]=' ';
x=x+1;
}
else
fail=1;
break;
}
case 'L':
{
if(y-1>=0)
{
puzzle[x][y]=puzzle[x][y-1];
puzzle[x][y-1]=' ';
y=y-1;
}
else
fail=1;
break;
}
case 'R':
{
if(y+1<5)
{
puzzle[x][y]=puzzle[x][y+1];
puzzle[x][y+1]=' ';
y=y+1;
}
else
fail=1;
break;
}
case '\n':
break;
case '\r':
break;
default:
fail=1;
break;
}
}
getchar();//接收0後面的回車。
if(fail)
{
printf("This puzzle has no final configuration.\n");
}
else
{
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
printf("%c",puzzle[i][j]);
if(j<4)
{
printf(" ");
}
}
printf("\n");
}
}
}
return 0;
}
習題3-6
注意點:
1、輸出的答案最後一行只換了一行,有可能會輸出兩行。
2、注意輸入時候,回車空格,scanf都會接收,通過增加額外的scanf避免回車輸入進資料陣列中。
3、如果要通過檔案測試,在windows系統的文字文件中,換行的表示為'/r/n',而不是'/n'。
#include<stdio.h>
#include<string.h>
int main(){
int r,c,puzzlei=1;
//FILE *fp,*fp2;
//fp=fopen("datain.txt","rb");
//fp2=fopen("dataout.txt","wb");
while(scanf("%d",&r)&&r!=0)
{ if(puzzlei!=1)
printf("\n");
int sqn=1,flag=1,i=0,j=0,sum;
char input[15][15];
int sn[15][15];
memset(sn,0,sizeof(sn));
char tmp;
scanf("%d",&c);
printf("puzzle #%d:\n",puzzlei++);
sum=r*(c+1);//使用檔案測試的時候需要準備/r/n兩個字元
scanf("%c",&tmp);//接收r,c後的回車
//fscanf("%c",&tmp);接收檔案的/r
while(sum--)//主要是要處理輸入的回車
{
scanf("%c",&tmp);
if(tmp!='\n'&&tmp!='\r')
{
input[i][j]=tmp;
if(input[i][j]!='*')
{
if(j-1<0||i-1<0||input[i][j-1]=='*'||input[i-1][j]=='*')
sn[i][j]=sqn++;
}
j++;
}
else if(tmp=='\n')
{
i++;
j=0;
}
}
printf("Across\n");
for(int i=0;i<r;i++)//橫向輸出
{
for(int j=0;j<c;j++)
{
if(input[i][j]!='*')
{
if(flag==1)
{
printf(" ");
if(sn[i][j]<10)
printf(" ");
printf("%d.",sn[i][j]);
flag=0;
}
printf("%c",input[i][j]);
if(input[i][j+1]=='*'||j+1==c)
{
flag=1;
printf("\n");
}
}
}
}
printf("Down\n");
flag=1;
for(int i=0;i<r;i++)//縱向輸出使用
{
for(int j=0;j<c;j++)
{
if(sn[i][j]!=0)
{
if(i-1<0||input[i-1][j]=='*')
{
printf(" ");
if(sn[i][j]<10)
printf(" ");
printf("%d.",sn[i][j]);
int k=i;
while(input[k][j]!='*'&&k<r)
{
printf("%c",input[k][j]);
k++;
}
printf("\n");
}
}
}
}
}
//fclose(fp);
//fclose(fp2);
return 0;
}
習題3-7
#include<stdio.h>
#include<string.h>
int main()
{
int k;
scanf("%d",&k);
while(k--)
{
char input[60][1200],res[1200];
char ch;
int m,n;
scanf("%d",&m);
scanf("%d",&n);
ch=getchar();
for(int i=0;i<m;i++)
{ int j=0;
while((ch=getchar())!='\n')
input[i][j++]=ch;
if(ch=='\n')
continue;
}
for(int i=0;i<n;i++)
{
int numA=0,numC=0,numG=0,numT=0;
for(int j=0;j<m;j++)
{
switch(input[j][i])
{
case 'A':
{
numA++;
break;
}
case 'C':
{
numC++;
break;
}
case 'G':
{
numG++;
break;
}
case 'T':
{
numT++;
break;
}
}
}
int tmp=numA;
if(numA>=numC&&numA>=numG&&numA>=numT)
{
res[i]='A';
printf("%c",'A');
}
if(numC>numA&&numC>=numG&&numC>=numT)
{
res[i]='C';
printf("%c",'C');
}
if(numG>numA&&numG>numC&&numG>=numT)
{
res[i]='G';
printf("%c",'G');
}
if(numT>numA&&numT>numC&&numT>numG)
{
res[i]='T';
printf("%c",'T');
}
if(i==n-1)
printf("\n");
}
int Han=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(input[j][i]!=res[i])
Han++;
}
}
printf("%d\n",Han);
}
return 0;
}
習題3-8解決本題目一般而言有兩個思路:
一是得到小數結果再進行判斷,如果這樣做相當困難,需要做字串的匹配,演算法時間複雜度很高,並且使用double,也不能儲存小數點後組都過的維數。
二是從過程著手,邊計算邊處理,從中發現,當在做除法的時候,除數不會變化,被除數一直改變。噹噹前被除數N曾經出現過時,就說明此時是迴圈節的結束點,而第一次出現的被除數N的地方則為迴圈節的開始點。
另外此題還是要注意輸出格式。
#include<stdio.h>
#include<string.h>
int main()
{
int a,b;
//FILE *fin,*fout;
//fin=fopen("datain.txt","rb");
//fout=fopen("dataout.txt","wb");
while(scanf("%d",&a)!=EOF)
{
int ans[3000],xhj[3000],bcs[3000];
int lenth,i=1,index=0;
memset(bcs,-1,sizeof(bcs));
memset(bcs,-1,sizeof(ans));
scanf("%d",&b);
printf("%d/%d = %d.",a,b,a/b);
a=a%b;
while(1)
{
bcs[a]=i++;
a=a*10;
ans[index++]=a/b;
a=a%b;
if(bcs[a]!=-1){
break;
}
}
//printf("%d %d",bcs[a],i);
lenth=i-bcs[a];
for(int m=0;m<bcs[a]-1;m++)
{
printf("%d",ans[m]);
}
printf("(");
if(i<50){
for(int m=bcs[a]-1;m<i-1;m++)
{
printf("%d",ans[m]);
}
}
else
{
for(int m=bcs[a]-1;m<50;m++)
{
printf("%d",ans[m]);
}
printf("...");
}
printf(")\n");
printf(" %d = number of digits in repeating cycle\n",lenth);
printf("\n");
}
//fclose(fin);
//fclose(fout);
return 0;
}
習題3-9思路:首先將問題轉換,要使t中刪除0個或者多個字元得到s。
需要滿足的條件為:t中有s的字元,並且順序與s的一樣。
在t中按照順序去找s裡面的字元,如果全部找到,則輸出Yes,否者輸出No。
注意事項:字元陣列宣告的時候,一定要大的,過小會造成,系統判斷為RunTime Error。
#include<stdio.h>
#include<string.h>
int main()
{
char s[1000000],t[1000000];
//FILE *fin,*fout;
//fin=fopen("datain.txt","rb");
//fout=fopen("dataout.txt","wb");
while(scanf("%s",s)!=EOF)
{
scanf("%s",t);
int lenths,lentht,j=0;
lenths=strlen(s);
lentht=strlen(t);
for(int i=0;i<lentht;i++){
if(t[i]==s[j]){
j++;
}
}
if(lenths==j)
printf("Yes\n");
else
printf("No\n");
}
//fclose(fin);
// fclose(fout);
return 0;
}
習題3-10思路:長方體是由長、寬、高組成,長方形的兩邊是長寬高三者中的兩者。那麼只需要統計長,寬,高的數量就能夠判斷。
本題的難點在於如果長方體中由兩個正方形、四個正方形、六個正方形的時候,需要再次判斷。
#include<stdio.h>
#include<string.h>
int main()
{
int m;
//FILE *fin,*fout;
//fin=fopen("datain.txt","rb");
//fout=fopen("dataout.txt","wb");
while(scanf("%d",&m)!=EOF)
{
int amount[3],ans[3];
memset(amount,0,sizeof(amount));
memset(ans,0,sizeof(amount));
ans[0]=m;
amount[0]++;
scanf("%d",&m);
ans[1]=m;
amount[1]++;
int n=10;
int j=-1;
while(n--)
{
scanf("%d",&m);
if(n%2==1)
{
if (ans[0]==m)
{
amount[0]++;
j=0;
}
else if (ans[1]==m)
{
amount[1]++;
j=1;
}
else if(ans[2]==m)
{
amount[2]++;
j=2;
}
else if(ans[2]==0)
{
ans[2]=m;
amount[2]++;
j=2;
}
else
{
j=-1;
}
}
else
{
if (ans[0]==m&&j!=0)
{
amount[0]++;
}
else if (ans[1]==m&&j!=1)
{
amount[1]++;
}
else if(ans[2]==m&&j!=2)
{
amount[2]++;
}
else if(ans[2]==0)
{
ans[2]=m;
amount[2]++;
}
}
}
if(amount[0]==4&&amount[1]==4&&amount[2]==4)
printf("POSSIBLE\n");
else if (amount[0]==6&&amount[1]==2&&amount[2]==4)
printf("POSSIBLE\n");
else if (amount[0]==4&&amount[1]==6&&amount[2]==2)
printf("POSSIBLE\n");
else if (amount[0]==6&&amount[1]==4&&amount[2]==2)
printf("POSSIBLE\n");
else if(amount[0]==6&&amount[1]==6)
printf("POSSIBLE\n");
else
printf("IMPOSSIBLE\n");
}
//fclose(fin);
//fclose(fout);
return 0;
}
習題3-11
問題分析:
本題目,可以認為是兩個陣列進行錯位匹配。這樣就會出現兩種情況:
1、陣列1匹配陣列2,陣列1比對開始點變化,陣列2需要全匹配。
2、陣列2匹配數字1,陣列2比對開始點變化,陣列1進行全匹配。
在匹配的過程中,又會出現兩種情況:
1、有陣列能夠匹配,那麼長度就為陣列1的長度加上陣列2的長度減去匹配的數字個數。
2、沒有一個數字能夠匹配,那麼長度就為陣列1的長度機上陣列2的長度。
其他情況:在實際上,可能會出現這樣一種情況。長條1和長條2匹配,長條2可以進行翻轉(也就是陣列逆序)和長條1進行匹配,得到最小值。本題並沒有考慮這種情況。
本題目:如果使用函式,會更加簡潔,但是考慮到這是第四章才講函式,暫時不用。
#include<stdio.h>
#include<string.h>
int main()
{
//FILE *fin,*fout;
//fin=fopen("datain.txt","rb");
//fout=fopen("dataout.txt","wb");
char m[1000],n[1000],dn[1000];
while(scanf("%s",m)!=EOF)
{
scanf("%s",n);
int start,flag,lenthm,lenthn;
start=0;
flag=1;
lenthm=strlen(m);
lenthn=strlen(n);
for(int i=0;i<lenthn;i++)
{
dn[lenthn-i-1]=n[i];
}
int i=0,j=0,p=0;
int min1,min2,min3,min4;
while(start<lenthm)
{
p=0;
flag=1;
i=start;
j=0;
while(j<lenthn&&i<lenthm)
{
int tmpm,tmpn;
tmpm=int(m[i++])-48;
tmpn=int(n[j++])-48;
if(tmpm+tmpn>3)
{
flag=0;
break;
}
else
p++;
}
if(flag==1)
{
min1=lenthn+lenthm-p;
break;
}
else
{
start++;
}
}
if(start==lenthm)
min1=lenthn+lenthm;
start=0;
while(start<lenthn)
{
p=0;
flag=1;
j=start;
i=0;
while(j<lenthn&&i<lenthm)
{
int tmpm,tmpn;
tmpm=int(m[i++])-48;
tmpn=int(n[j++])-48;
if(tmpm+tmpn>3)
{
flag=0;
break;
}
else
p++;
}
if(flag==1)
{
min2=lenthn+lenthm-p;
break;
}
else
{
start++;
}
}
if(start==lenthn)
min2=lenthn+lenthm;
if(min1<min2)
printf("%d\n",min1);
else
printf("%d\n",min2);
}
//fclose(fin);
//fclose(fout);
return 0;
}
習題3-12
問題分析:本題本質是一個二進位制十進位制轉換問題。可以從兩個角度考慮。
1、先將輸入的十進位制轉為二進位制,然後再通過轉化的二進位制數來求得表示這個二進位制需要的尾數個數和階碼個數。
2、將二進位制轉為十進位制,題目已經告訴了表示這個二進位制數的尾數個數和階碼個數。
具體實施時候,會發現如果採用角度1進行編碼,將遇到以下兩個問題:
1、列舉次數太多,時間過長失敗。解決方法:暫無。
2、輸入溢位,計算溢位。
因為時間太長,導致這個角度的解決方法暫時擱淺,那麼角度2來解決這個問題,
目標:計算當M(尾數的個數)為i時,E(階碼的個數)為j的時候,所能夠表示的最大(最小)十進位制數。
問題:直接轉化成十進位制數還是會溢位。
解決方案:將這個十進位制數分成階碼和尾數分別表示。(可行)
首先求與M(尾數的個數)為i時,E(階碼的個數)為j能表示的最大二進位制數相等的10的x次方數。(x為浮點數)。
那麼x的整數部分就為M(尾數的個數)為i時,E(階碼的個數)為j時的所能表示的最大十進位制數的階碼(即為輸入中e後面的數)
10的x小數部分次方就為十進位制數的尾數,當x=0時,10的x次數為1,當x=1時,10的x次方為10,那麼10的x小數部分次方的範圍在1到10.
但是輸入是0到10,所以還需要一次轉換。
輸入值能採用字元輸入再轉換,以避免溢位。
#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
//FILE *fin,*fout;
//fin=fopen("datain.txt","rb");
//fout=fopen("dataout.txt","wb");
double M[15][35];
long int E[15][35];//m為尾數,E為階碼
for(int i=0;i<=9;i++)
{
for (int j=1;j<=30;j++)
{
double m,e,tmp;
m=1-pow(2,-1-i);//用第i位表示尾數時,尾數的最大值
e=pow(2,j)-1;
tmp=log10(m)+e*log10(2);//通過對數公式,求得10為的底的指數(小數)
E[i][j]=tmp;//因為E是整形陣列,那麼自會將tmp的整數部分存入E中。
M[i][j]=pow(10,tmp-E[i][j]);
}
}
char input[100];
while(scanf("%s",input)&&!(input[0]=='0'&&input[1]=='e'&&input[2]=='0'))
{
int lenthin,ein,e;//定位e的位置
double m10d;
int e10d=0;
lenthin=strlen(input);
for(int i=0;i<lenthin;i++)
{
if(input[i]=='e')
ein=i;
}
m10d=(int(input[0])-48)*pow(10,0);
for(int i=2;i<ein;i++)
{
m10d=m10d+(int(input[i])-48)*pow(10,-i+1);
}
for(int i=ein+1;i<lenthin;i++)
{
e10d=e10d+(int(input[i])-48)*pow(10,lenthin-i-1);
}
if(m10d<1)
{
e10d=e10d-1;
m10d=m10d*10;
}
for (int j=1;j<=30;j++)
{
for(int i=0;i<=9;i++)
{
if(e10d<=E[i][j]&&fabs(m10d-M[i][j])<1e-5)
{
printf("%d %d\n",i,j);
break;
}
}
}
}
//fclose(fin);
//fclose(fout);
return 0;
}
相關文章
- C語言入門經典(第5版)C語言
- Go語言入門經典第18章Go
- 演算法競賽入門經典訓練指南 pdf演算法
- C語言入門經典(第4版)電子書pdf下載C語言
- C#語言入門詳解(劉鐵錳)---泛型C#泛型
- C語言演算法競賽入門(二)—陣列元素移動、排序問題、猴子選大王問題C語言演算法陣列排序
- 演算法競賽C++快速入門演算法C++
- kaggle再一次入門~經典入門級競賽~Titanic
- c 語言指標操作經典問題指標
- 2019年c語言經典面試題目C語言面試題
- 經典排序演算法的 C語言 | Java 實現排序演算法C語言Java
- JavaScript函數語言程式設計入門經典JavaScript函數程式設計
- c語言入門C語言
- 每日一題:C語言經典例題之雞兔同籠每日一題C語言
- C語言_入門例題_PAGE1C語言
- 經典加密演算法入門-RSA加密演算法
- 《怎樣解題:數學競賽攻關寶典(第3版)》勘誤
- PAT-B 1059 C語言競賽【模擬】C語言
- C語言入門基礎C語言
- 10個經典C語言演算法—零基礎小白必學C語言演算法
- Python程式設計入門——基礎語法詳解(經典)Python程式設計
- C語言從入門到精通光碟原始碼(清華大學出版社)原始碼下載C語言原始碼
- 《C 語言入門教程》釋出了
- 五種C語言非數值計算的常用經典排序演算法C語言排序演算法
- C語言必須要記住的經典程式C語言
- csharp入門經典CSharp
- 【CSDN競賽第24期】贏熱門圖書《演算法競賽》和定製周邊演算法
- 20201215-經典基礎C語言題01-三個數排大小C語言
- C語言貪吃蛇原始碼C語言原始碼
- [C語言] 第一章|C語言入門第一課C語言
- C語言入門很簡單pdfC語言
- C++語言菜鳥快速入門C++
- 入門輸出Hello World!——C語言C語言
- 《Flutter 入門經典》之“Flutter 入門 ”Flutter
- 資訊學競賽免費課程之C++語法入門網課影片C++
- 《明解C語言》第三章學習筆記C語言筆記
- C語言入門題-7-1 最大和最小 (10分)C語言
- R語言經典統計分析R語言
- C語言解決排序問題C語言排序