算法练习3
来源:互联网 发布:js自动中跳转页面 编辑:程序博客网 时间:2024/06/07 20:07
1.生成元
题目
如果 x 加上 x 的各个数字之和得到的 y,就说 x 是 y 的生成元。给出 n (1 <= n <= 100000),求最小生成元。无解输出 0。例如,n = 216,121,2005 时的解分别为 198,0,1979。
分析:
假设所求生成元为m,不难发现m<n,只需要枚举所有的m<n,看看有没有哪个数是n的生成元。此做法效率不高,只需要一次性枚举100000内的所有正整数吗,标记”m加上m的各个数字之和得到的数得到的数又一个生成元是m“最后查表即可
#include<stdio.h>
#include<string.h>
#define maxn 100005
int ans[maxn];
int main()
{
int T,n;
memset(ans,0,sizeof(ans));
for(int m=1;m<maxn;m++)
{
int x=m,y=m;
while(x>0)
{
y+=x%10;
x/=10;
}
if(ans[y]==0||m<ans[y])ans[y]=m;//从1-maxn找每个数最小生成元,没有为0,m<ans[y]用来寻找最小的生成元
}
scanf("%d",&T);
while(T--)//输入T个数
{
scanf("%d",&n);
printf("%d\n",ans[n]);//输出每个数的最小生成元
}
return0;
}
2.环状序列长度为n的换证串有n种表示法,分别为从某个位置开始顺时针得到。例如图:
有10种表示:CGAGTCAGCT,GAGTCAGCTC,AGTCAGCTCG等。在这些表示法中,字典序最小的成为“最小表示”。
输入一个长度为n(n<=100)的环状DNA串(只包含A,C,G,T)的一种表示法你的任务是输出该环状串的最小表示。例如,CTCC的最小表示是CCCT。CGAGTCAGCT的最小表示为AGCTCAGTC。
【分析】
本题出现了一个新概念,字典序。就是字符串在字典中的顺序。一般对于两个字符串,从第一个字符开始比较。当某一个的字符不同时,该位置字符较小的串,字典序较小(例如,abc比bcd小);如果其中一个字符串已经没有更多字符,但另一个字符串还没结束,则较短的字符串的字典序较小(例如,hi比history小)。字典序的概念可以推广到任意序列,例如,序列1,2,4,7,比1,2,5小。
学会了字典序的概念之后,本题就不难解决了:就像“求n个元素中的最小值”一样,用变量ans表示目前位置,然后不断更新ans。
第一种简便的算法:
#include <stdio.h>
#include <string.h>
const int maxn=100+10;
char s[maxn];
char stemp[maxn][maxn];
int main(){
int T;
int len;
int i;
char minc;
int mini;
int count;
int j;
scanf("%d",&T);
while(T--){
scanf("%s",s);
len=strlen(s);
minc=s[0];
count=0;
for(i=0;i<len;i++){//找出字典序列最小的字母
if(minc>s[i])
minc=s[i];
}
for(i=0;i<len;i++)
if(minc==s[i]){//根据最小字母,形成不同子串
for(j=0;j<len;j++){
stemp[count][j]=s[(i+j)%len];
}
stemp[count][j]='\0';
count++;
}
mini=0;
for(i=0;i<count;i++){//在不同子串中,寻找字典序列最小的串
//if(strcmp(stemp[mini],stemp[i])==0)//WA
if(strcmp(stemp[mini],stemp[i])>0)//AC
mini=i;
}
printf("%s\n",stemp[mini]);
}
return 0;
}
#include<stdio.h>
#include<string.h>
constint maxn = 100+10;
char s[maxn];
int less(constchar *s,int p,int q){
int i;
int len=strlen(s);
for(i=0;i<len;i++){
if(s[(p+i)%len]!=s[(q+i)%len])
return s[(p+i)%len]<s[(q+i)%len];
//若s[(p+i)%len]<s[(q+i)%len],则返回为正,ans=i
//ans表示目前为止,字典符最小串在输入串的起始位置
//比较完了首字母,在比较确定的第二个字母
}
return 0;
}
int main(){
int T;
int i;
int ans;
int len;
scanf("%d",&T);
while(T--){
ans=0;
scanf("%s",s);
len=strlen(s);
for(i=0;i<len;i++){
if(less(s,i,ans)){
ans=i;
}
}
for(i=0;i<len;i++)
putchar(s[(ans+i)%len]);
putchar('\n');
}
return 0;
}