LDU 软件工程算法课程习题(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/passer__/article/details/82316858

exm:独立思考万岁,代码如果在你们OJ过不去,说明你们的服务器比我们还垃圾,那么建议你们更换服务器。

本人代码丑,如果对于哪里不理解而且没加注释,可以留言。

问题 A: 数字统计问题

题目描述

给定一本书,其中包含n页,计算出书的全部页码中用到了多少个数字0…9?页码从1开始

输入

一个整数n,代表页码总数。(0<=n<=106)

输出

十行,每行一个整数,分别表示0~9每个数字出现的次数

样例输入

11

样例输出

1
4
1
1
1
1
1
1
1
1

思想:枚举当前数字和后边的数字,对于比当前为数小的那个数,后边肯定有10^后边位数,对于当前就是后边的和。

,对于后边位数那个数出现的次数等于后边的长度*10^长度减一(自行检验),还需要减去多余的0

#include<bits/stdc++.h>
using namespace std;
int vis[10];
int main()
{
    int page;
    scanf("%d",&page);
    int len=0;
    int temp=page;
    while(temp)
    {
        len++;
        temp=temp/10;
    } 
    for(int i=0;i<len;i++)
    { 
        int A=(page/(int)pow(10,len-i-1))%10;//数 
        int B=page%(int)pow(10,len-i-1);//后
        vis[A]+=B+1;
        for(int j=0;j<A;j++)
        {
            vis[j]+=pow(10,len-i-1);
            for(int k=0;k<10;k++)
                vis[k]+=(len-i-1)*(int)pow(10,len-i-2);
        }   
    } 
    for(int i=0;i<len;i++)
        vis[0]-=(int)pow(10,i);
    for(int i=0;i<10;i++)
        printf("%d\n",vis[i]);  
    return 0;
} 

问题 D: 2011的倍数

题目描述

给定一个正整数n,多少个1组成的整数可以被n整除?

输入

一个整数n(1<=n<=105) 

输出

一个正整数,表示数字1的个数。如果无解,请输出-1

样例输入

2011

样例输出

670

直接模拟就好了,大概是52W个1组成的数后边如果没有就是无解,2记住要特判下。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long n;
    scanf("%lld",&n);
    if(n==2)
        printf("-1\n");
    else
    {
        int ans=1;
        long long temp=1;
        while(1)
        {
            if(temp%n==0)
            {
                printf("%d\n",ans);
                break;
            }
            temp=temp%n*10+1;
            ans++;
            if(ans>=520000)
            {
                printf("-1\n");
                break;
            }
        }
    } 
    return 0;
}

问题 E: 最多约数问题

题目描述

正整数 x 的约数是能整除x的正整数,其约数的个数记为div(x),例如div(10)=4。设 a 和 b 是两个正整数,找出 a 和 b 之间(包含a,b)约数个数最多的数 x 的约数个数

输入

两个正整数a和b,(1<=a<=b<=105)

输出

一个正整数表示答案。

样例输入

1 36

样例输出

9

思想:素因子打表,最大不会1e3超过1e3不会出现2个

#include<bits/stdc++.h>
using namespace std;
int vis[1005];
int num[1005];
int cnt;
void init()
{
    vis[1]=1;
    for(int i=2;i<=1000;i++)
    {
        if(vis[i]==0)
        {
            num[cnt++]=i;   
            for(int j=i+i;j<=1000;j+=i)
                vis[j]=1;
        } 
    } 
} 
int main()
{
    init();
    int a,b;
    int Max=0;
    scanf("%d%d",&a,&b);
    for(int i=a;i<=b;i++)
    {
        int temp=i;
        int sum=1;
        for(int j=0;j<cnt && num[j]<=temp;j++)
        {
            int ans=0;
            while(temp%num[j]==0)
            {
                ans++;
                temp=temp/num[j];
            }
            sum*=(ans+1);   
        }
        Max=max(Max,sum);
    }
    printf("%d\n",Max);
    return 0;
}

dfs爆搜

#include<iostream>
using namespace std;
typedef long long LL;
  
const int a[20]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
int T1,T;
LL n,ans;
  
void DFS(int k,LL sum,LL ni,int m);
int main()
{
    ios::sync_with_stdio(false);
    ans=1;
    cin>>T>>n;
    DFS(0,1,1,15);
    cout<<ans<<endl;
    return 0;
}
  
void DFS(int k,LL sum,LL ni,int m)
{
    if(k>16) return;
    ans=max(ans,sum);
    for(int i=1;i<=m;++i)
        if(ni<=n/a[k]){
            ni*=a[k];
            DFS(k+1,sum*(i+1),ni,i);
        }else   break;
}

问题 F: 最大间隙问题

题目描述

给定 n 个实数,求这n个实数在数轴上相邻2个数之间的最大差值,设计解最大间隙问题的线性时间算法(时间复杂度为O(n))。 

输入

第一行一个正整数n(2<=n<=2×107) 
第二行n个实数,数据保证这些实数只有一位小数。 

输出

一个实数,保留1位小数。

样例输入

5
2.3  3.1  7.5  1.5  6.3

样例输出

3.2

思想:鸽笼原理 模拟下就好,注意特判下都在一个区间的情况。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e7+10;
double num[maxn];
int sum[maxn];//记录数量 
double Maxx[maxn]; //储存最大值
double Minn[maxn];//储存最小值 
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%lf",&num[i]);
    double Max=-1;
    double Min=1e30;
    for(int i=0;i<n;i++)
    {
        Max=max(Max,num[i]);
        Min=min(Min,num[i]);
    } 
    double Gap=(Max-Min)/((n-1)*1.0);//间隙大小 
    if(Gap==0.0)
    {
        printf("0.0\n");
        return 0;
    }
    for(int i=0;i<n;i++)
    {
        int temp=(int)((num[i]-Min)/(Gap))+1;
        //printf("%d %lf\n",temp,num[i]); 
        if(Maxx[temp]==0)
            Maxx[temp]=num[i];
        else   
            Maxx[temp]=max(Maxx[temp],num[i]);
        if(Minn[temp]==0)
            Minn[temp]=num[i];
        else
            Minn[temp]=min(Minn[temp],num[i]);
        sum[temp]++; 
    }
    double ans=Maxx[1]-Minn[1];
    double temp=Maxx[1];
    for(int i=2;i<=n;i++)
    {
        if(sum[i]>=1)
        {
            ans=max(ans,Minn[i]-temp);
            temp=Maxx[i];
        }
    }
    printf("%.1lf\n",ans);
    return 0;
}

问题 G: 字典序问题

题目描述

在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表A由26个小写字母组成。该字母表产生的升序字符串中字母从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现1次。例如,a,b,ab,bc,xyz等字符串都是升序字符串。现在对字母表中产生的所有长度不超过6的升序字符串,计算它在字典中的编码。

… 

ab 

ac 

 

27 

28 

输入

第一行一个整数T,表示测试组数。 
接下来T行,每行一个长度不超过6的升序字符串(仅含小写字母)。 

输出

输出T行,每行一个整数代表答案。

样例输入

2
a
b

样例输出

1
2

思想:直接递归找肯定T,所以提前递归打表,直接呜呜呜的算就好了。

#include<bits/stdc++.h>
using namespace std;
char str[10];
int dp[30][30]; 
int find(int index,int len)
{   
    int sum=0;
    if(len==1)
        return 1;
    for(int j=index+1;j<=26;j++)
    {
        if(dp[j][len-1])
            sum+=dp[j][len-1];
        else
            sum+=find(j,len-1);
    }
    dp[index][len]=sum;
    return sum;
} 
void init()
{
    for(int i=1;i<=6;i++)
    {
        for(int j=1;j<=26;j++)
            dp[j][i]=find(j,i);
    }
}
int check(char str[])
{
    int sum=0;
    int len=strlen(str);
    for(int i=1;i<len;i++)//长度小于len的 
        for(int j=1;j<=26;j++) 
            sum+=dp[j][i];
   
    int k=str[0]-'a'+1;
    for(int i=1;i<k;i++)//比第一位小的所有的 
        sum+=dp[i][len]; 
               
    int count=k;//第一位开头的那个 
    for(int i=1;i<len;i++)//枚举后边的len-1位 
    {
        int temp=str[i]-'a'+1;
        int length=len-i;        //后边的长度 
        for(int j=count+1;j<temp;j++)//保证升序,每一位都比上次的大 
            sum+=dp[j][length]; 
        count=temp; 
    }
    return sum+1;
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",str);
   
        int temp=check(str);
        printf("%d\n",temp);    
    }
    return 0;
}

问题 H: 金币阵列问题

题目描述

n×m(m<=100,n<= 100)个金币在桌面上排成一个n列的金币阵列。每一枚金币或正面朝上或背面朝上。用数字表示金币状态,0表示金币正面朝上,1 表示背面朝上。金币阵列游戏的规则是:

(1)每次可将任一行金币翻过来放在原来的位置上; 

(2)每次可任选2 列,交换这2 列金币的位置。 
给定金币阵列的初始状态和目标状态,编程计算按金币游戏规则,将金币阵列从初始状态变换到目标状态所需的最少变换次数。 

输入

每组数据的第1行有2个正整数n和m。以下的n行是金币阵列的初始状态,每行有m 个数字表示该行金币的状态,0 表示金币正面朝上,1 表示背面朝上。接着的n行是金币阵列的目标状态。

输出

输出最少变换次数(规则1和2使用的次数之和),无解时输出-1。

样例输入

4 3
1 0 1
0 0 0
1 1 0
1 0 1

1 0 1
1 1 1
0 1 1
1 0 1

样例输出

2

思想:先考虑后边的每列跟第一列交换,因为只能交换列或者翻转某一行,所以只要把第一列定型之后,后边只能交换列,不能在动一行了,否则会影响整个局面,因此,就把第一列跟所有的列交换一次,然后交换后,考虑A矩阵和某一列交换使当前列变成题目要求的列一样,就这样一列一列转换好,如果最终可以转换好,那么就保存下交换的次数,如果不行就不管了,最后根据次数来判断是否OK了。很多情况break掉了 所以时间复杂度卡不到1e8

#include<bits/stdc++.h>
using namespace std;
const int INF = 1<<30; 
int a[110][110];
int b[110][110];
int tmp[110][110];
int m,n;
int check(int j,int k)//比较A的k列和b的j列是否相等 
{
	for(int i=0;i<n;i++)
		if(a[i][k]!=b[i][j])
			return 0;
	return 1;
}
void find()
{
    int flag;//标记是否OK 
    int ans=INF;//最少交换次数 
    int Count=0;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			tmp[i][j]=a[i][j];
    for(int i=0;i<m;i++)
    {
    	for(int j=0;j<n;j++)//将当前i列与第一列进行交换 
    		swap(a[j][i],a[j][0]);
        if(i!=0)
            Count++;
        for(int j=0;j<n;j++)//判断是否第一列已经相等 
        {
            if(a[j][0]!=b[j][0])
            {
            	for(int k=0;k<m;k++)
            		a[j][k]^=1;//j行m列都变换 
                Count++;
            } 
        }
        flag=1;
		//第一列肯定是OK了
        for(int j=1;j<m;j++)//考虑交换列 
        {
            flag=0;
            for(int k=j;k<m;k++)//b数组为参考 
            {
                if(check(j,k))  //比较a的第k列和b的第j列是否相等
                {
                    if(k!=j)
                    { 
                        Count++;
                        for(int kk=0;kk<n;kk++)
							swap(a[kk][k],a[kk][j]);
                    } 
                    flag=1; //找到可以交换的了  	
                    break;
                }
            }
            if(flag==0)//没办法交换 
                break;
        }
        if(flag==1 && ans>Count)
            ans=Count;
        Count=0;
        for(int j=0;j<n;j++)
			for(int k=0;k<m;k++)
				a[j][k]=tmp[j][k];
    }
    if(ans==INF)
		printf("-1\n");
	else
		printf("%d\n",ans); 
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%d",&a[i][j]);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%d",&b[i][j]);
    find();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/passer__/article/details/82316858