算法练习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种表示法,分别为从某个位置开始顺时针得到。例如图:\epsfbox{p3225.eps}

有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;
}


/*
C/C++函数,比较两个字符串
设这两个字符串为str1,str2,
若str1==str2,则返回零;
若str1<str2,则返回负数;
若str1>str2,则返回正数。*/
书上的代码:

#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;

}