中国矿业大学-算法概论-作业1

问题 A: algorithm-锯木棒

题目描述

xiaok大佬最近再雇佣工人给他掰木棒。把一根长为L的木棒锯成两段,他需要支付给工人L元钱。xiaok大佬一开始只有长为L的一根木棒,他想把它锯成n段,每段长度分别为L1,L2,...,Ln,问xiaok大佬最少要付给工人多少钱?

输入

第一行两个整数n,L(1<n<103,n<L<109) 第二行n个整数L1,L2,...,Ln(0<Li<L,且保证L1+L2+...+Ln=L)

输出

输出一个整数,表示最小花费

样例输入 Copy)

3 21
8 5 8

样例输出 Copy)

34
#include<bits/stdc++.h>
using namespace std;
struct cmp
{
    bool operator()(int& a,int& b)
    {
        return a>b;
    }
};
int main()
{
    priority_queue<int,vector<int>,cmp> queue;
    int n,L,tmp,sum=0, a, b;
    cin>>n>>L;
    for(int i=0;i<n;i++)
    {
        cin>>tmp;
        queue.push(tmp);
    }
    while(queue.size()>1)
    {
        a=queue.top();
        queue.pop();
        b=queue.top();
        queue.pop();
        sum=sum+a+b;
        queue.push(a+b);
    }
    cout<<sum<<endl;
}

问题 B: algorithm-最长公共子序列

题目描述

一个字符串A的子串被定义成从A中顺次选出若干个字符构成的串。如A=“cdaad" ,顺次选1,3,5个字符就构成子串" cad" ,现给定两个字符串,求它们的最长共公子串。

输入

第一行两个字符串用空格分开。两个串的长度均小于2000 。

输出

最长子串的长度。

样例输入 Copy)

abccd aecd

样例输出 Copy)

3
#include <bits/stdc++.h>
#include<string> 
using namespace std;
char x[2010], y[2010];
int m, n;
int c[2021][2010]={0};
void Lcs_Length()
{
    for (int i=1; i<=m; i++){
        for (int j=1; j<=n; j++)  
        {
            if (x[i-1]==y[j-1])
            {
                c[i][j] = c[i-1][j-1] + 1;
            }    
            else if (c[i-1][j] >= c[i][j-1])
            {   
                c[i][j] = c[i-1][j]; 
            }
            else 
            {   
                c[i][j] = c[i][j-1];
            }
            
        }
    }
​
    cout<<c[m][n];
    
 } 
int main(){
    cin>>x>>y;
    m = strlen(x);
    n = strlen(y);
    Lcs_Length();
    return 0;
    
}

问题 C: algorithm-矩阵连乘

题目描述

给定n个矩阵{A1,A2,...,An},及m个矩阵连乘的表达式,判断每个矩阵连乘表达式是否满足矩阵乘法法则,如果满足,则计算矩阵的最小连乘次数,如果不满足输出“MengMengDa“。

输入

输入数据由多组数据组成(不超过10组样例)。每组数据格式如下: 第一行是2个整数n (1≤n≤26)和m(1≤m≤3),表示矩阵的个数。 接下来n行,每行有一个大写字母,表示矩阵的名字,后面有两个整数r和c,分别表示该矩阵的行数和列数,其中1<r, c<100。 第n+1行到第n+m行,每行是一个矩阵连乘的表达式(2<=矩阵个数<=100)。

输出

对于每个矩阵连乘表达式,如果运算不满足矩阵乘法法则的情况(即左矩阵列数与右矩阵的行数不同),则输出“MengMengDa”,否则输出最小矩阵连乘次数。

数据保证结果不超过1e9。

样例输入 Copy)

3 2
A 10 100
B 5 50
C 100 5
ACB
ABC

样例输出 Copy)

7500
MengMengDa
#include <bits/stdc++.h>
#include<string> 
using namespace std;
struct node{
    char name;
    int r=0;
    int c=0;
}a[30];
        
int convert(char x, int n) {
    int i;
    for( i=0; i<n; i++) if(a[i].name == x) break;
    return i;
}
long int  MatrixCharin(int *p, int n,long  int m[][101])
{
    for(int i=0;i<=n;i++) m[i][i]=0; 
    for(int r=2; r<=n; r++) // r个矩阵相乘 
        for(int i=1; i<=n-r+1; i++)
        {
            int j = i+r-1; // 本循环的最后一个矩阵 
            m[i][j] = m[i][i] + m[i+1][j] + p[i-1]*p[i]*p[j]; // 假设最优划分位于i处 
            for(int k= i+1; k<j; k++) // 变化最优分割的位置, 逐一测试 
            {
                long int  t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
                if(t < m[i][j] ) m[i][j] = t; // 如果更优替换原位置 
             } 
        }
    return m[1][n];
}
int main() {
    int m, n; 
    char str[3][101]; // 输入的矩阵字符串
    long int x[101][101];
    int p[3][101];
    int flag[3];
    while(cin>>n>>m){
        memset(str, 0, sizeof(' '));
        
         for(int i=0; i < n; i++) cin>>a[i].name>>a[i].r>>a[i].c;
         for(int i=0; i< m ; i++)
         {
            cin>>str[i];
            flag[i]=0;
            for(int k=0; k< strlen(str[i]); k++)
            {
                if(k==0){
                    p[i][k] = a[convert(str[i][k], n)].r;
                    p[i][k+1] = a[convert(str[i][k], n)].c;
                }
                else {
                    if(p[i][k] == a[convert(str[i][k], n)].r){
                        p[i][k+1] = a[convert(str[i][k], n)].c;
                    }
                    else{
                        flag[i]=1;
                    }   
                }
            }
        }
         for(int i=0; i<m ; i++)
         {
            if(flag[i] == 1){
            cout<<"MengMengDa"<<endl;
            }
            else {
                long int result = MatrixCharin(p[i], strlen(str[i]), x);
                cout<<result<<endl;
            }
         }
    }
    return 0;
}
​

问题 D: algorithm-沙子的质量

题目描述

设有N堆沙子排成一排,其编号为1,2,3,…,N(N< =300)。每堆沙子有一定的数量,可以用一个整数来描述,现在要将N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为1 3 5 2我们可以先合并1、2堆,代价为4,得到4 5 2又合并1,2堆,代价为9,得到9 2,再合并得到11,总代价为4+9+11=24,如果第二步是先合并2,3堆,则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22;问题是:找出一种合理的方法,使总的代价最小。输出最小代价。

输入

第一行一个数N表示沙子的堆数N。 第二行N个数,表示每堆沙子的质量。 a[i]< =1000。

输出

合并的最小代价。

样例输入 Copy)

4
1 3 5 2

样例输出 Copy)

22
#include <bits/stdc++.h>
using namespace std;
int dp[301][301]; // 最小代价
int MatrixCharin(int *a, int n){
    memset(dp, 0, sizeof(dp));
    for(int r=2;r<=n;r++){ // 共几个沙堆相加
        for(int i=1;i<=n-r+1;i++){
            int j=i+r-1; // 本循环的最后一个沙堆
            dp[i][j] = dp[i][i] + dp[i+1][j]+ a[j]-a[i-1];
            for(int k=i+1;k<j;k++){
                int t = dp[i][k] + dp[k+1][j] + a[j]-a[i-1];
                if(t < dp[i][j]){
                    dp[i][j] = t;
                } 
            }
        }
    }
    return dp[1][n];
}
int main(){
    int n;
    cin>>n;
    int *a = new int[n];
    a[0]=0;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
        a[i]= a[i]+a[i-1];
    }
    cout<<MatrixCharin(a, n);
    delete[] a;
    return 0;
} 
​

问题 E: algorithm-求第k小

题目描述

给定n(1<=n<=1000000)个元素,求第k小数(1<=k<=n)。

输入

一组样例。第一行输入两个整数n和k。第二行输入n个不同的int范围内的数。

输出

输出一行,输出第k小数。

样例输入 Copy)

5 2
1 5 3 2 4

样例输出 Copy)

2
#include<bits/stdc++.h>
#include <stdlib.h> 
#include <time.h>  
using namespace std;
​
const int t = 1000000;
int s[t];
​
// 产生随机整数 
int random(int begin,int end)
{
    srand((unsigned)time(NULL));
    return rand()%(end - begin + 1) + begin;
}
​
// 将小于基点的放在基点左侧,大于的放在右侧 
int Partition(int a[], int p, int r){
    int i=p;
    int j=r+1;
    int x = a[p];
    while(1){
        while(a[++i]<x && i<r);
        while(a[--j] > x);
        if(i>=j) break;
        swap(a[i], a[j]);
    }
    a[p] = a[j];
    a[j] = x;
    return j; // 返回排序后基点序号 
}
// 随机选择基准点 
int RandomizedPartition(int a[], int p, int r){
    int i = random(p, r);
    swap(a[i], a[p]);
    return Partition(a, p, r); 
} 
​
int RandomizedSelect(int a[], int p, int r, int k){
    if(p==r) return a[p];
    int i= RandomizedPartition(a, p, r);
    int j = i - p + 1; // 在基点左侧的数的个数 
    if(k <= j) return RandomizedSelect(a, p, i, k);  // 在基点的左侧找 
    else return RandomizedSelect(a, i+1, r, k-j); // 在基点右侧的 找第k-j小 
}
​
int main(){
    int n,k,sum=0;
    cin>>n>>k;
    for(int i=0; i<n; i++) cin>>s[i];   
    sum = RandomizedSelect(s, 0, n-1, k);
    cout<<sum;
    return 0;
}
 
​
​

问题 F: algorithm-快速幂

题目描述

输入

多组测试样例,最多50组。每组测试样例给定一个整数x(1<=x<=25000)

输出

对每个样例,输出一行,代表f(x)对100000007取余的结果。

样例输入 Copy)

3
4
5

样例输出 Copy)

33
289
3414
#include<bits/stdc++.h> 
using namespace std;
const long long  tmp = 100000007; // 对它取余 
int fastPower(long long base, long long  power) {
    long long result = 1;
    while (power > 0) {
        if (power & 1) {//此处等价于if(power%2==1) 二进制最后一位与1相与
            result = result * base % tmp;
        }
        power >>= 1;//此处等价于power=power/2 ,对二进制右移一位
        base = (base * base) % tmp;
    }
    return result;
}
int main(){
    long long  x;
    while(cin>>x){
        long long sum = 0;
        for(long long  i=1;i<=x;i++){
            sum = sum + fastPower(i, i);
            sum=sum%tmp;
        }
        cout<<sum + 1<<endl;
    }
    return 0;
}
 
​
​

问题 G: algorithm-排列问题

题目描述

输入一个可能含有重复字符的字符串,打印出该字符串中所有字符的全排列。

输入

单组测试数据,输入数据是一个长度不超过10个字符的字符串,以逗号结尾。

输出

打印出该字符串中所有字符的全排列。以字典序顺序输出,用空格分隔。

样例输入 Copy)

abc,

样例输出 Copy)

abc acb bac bca cab cba
#include<iostream>
#include<string.h>
using namespace std;
// 交换函数 
void Swap(char& a, char& b){ 
    char c = a;
    a = b;
    b = c;
}
​
void Sort(char *arr,int begin,int end){
    int i,j;
    for(i=begin;i<=end;i++){
        for(j=i+1;j<=end;j++){
            if(arr[i]>arr[j]){
                Swap(arr[i],arr[j]);
            }
        }
    }
}
​
// 全排列  递归 
void Rank(char* b, int start, int end){
    if (start == end){
        for (int i = 0; i <= end; i++) cout<<b[i]; 
        cout<<" "; 
    }
    else{ 
        // 固定首字符,对剩下的字符进行全排列,然后回归,切换首字符 ,直到从start到end的字符全被切换 
        for (int i = start; i <= end; i ++){
            Swap(b[i], b[start]);  
            Sort(b, start + 1, end); // 对交换后所有元素进行排序 
            Rank(b, start + 1, end); // 排列 
            Sort(b, start + 1, end); // 还原排列之前的顺序 
        }
    }
}
 
​
int main()
{
    char a[10];
    cin>>a;
    int n = strlen(a);
    // 以逗号结尾 ,传n-1个值 
    Sort(a, 0, n-2);
    Rank(a, 0, n-2);
    return 0;
}
​
​

问题 H: algorithm-进制转换

题目描述

输入一个十进制正整数,然后输出它所对应的八进制数。

输入

输入一个十进制正整数n(1≤n≤106) 。

输出

输出n对应的八进制数,输出在一行。

样例输入 Copy)

10

样例输出 Copy)

12
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
    int x,y;
    cin>>x;
    vector <int> z; 
    int i=0;
    while(x){
        y = x % 8;
        z.push_back( y );
        x = x / 8;
        i++;
        if(x<8){
            z.push_back(x);
            x = 0;
        }
    }
    reverse(z.begin(), z.end()); // 对容器z中的元素倒序 
    for(int i = 0; i < z.size(); i++)
        cout<<z[i];
    return 0;
}
​

问题 I: algorithm-奶牛的聚会

题目描述

农历新年马上就要到了,奶牛们计划举办一次聚会庆祝新年的到来。但是,奶牛们并不喜欢走太远的路,这会给他们的聚会带来消极情绪,当一头奶牛的消极指数为Wi,他参加聚会所需行走的距离为si,那么他就会给聚会带来Si3*Wi的消极情绪。所有奶牛所在位置都在一条直线上,已知所有奶牛的坐标和消极指数,求如何确定聚会地点,使得所有奶牛给聚会带来的消极情绪之和最小,输出消极情绪之和的最小值。

输入

第一行包含一个整数 Ca(Ca<=20) ,表示有 Ca 组测试数据。

对于每组测试数据:第一行包含一个整数n(1<=n<=50000) ,表示奶牛的数量。接下来 n 行每行包含两个浮点数Si和wi (-106<=Si<=106, 0<Wi<15)。

输出

对于每组测试数据,输出 "Case #c: ans" ,其中c表示测试数据编号,ans表示消极情绪之和的最小值,结果四舍五入为一个整数。

样例输入 Copy)

1
5
0.9 2
1.4 4
3.1 1
6.2 1
8.3 2

样例输出 Copy)

Case #1: 300
#include <iostream>
#include<cmath> 
typedef long long ll;
using namespace std;
double *s = NULL;
double *w = NULL;
int x;
// 定义的函数计算情绪之和 
double F(double t){
    double sum = 0;
    for(int i=0;i<x;i++){
        sum += pow(abs(s[i]-t), 3)*w[i];
    }
    return sum;
}
int main(){
    int n, k;
    cin>>n; // n组测试数据 
    k = n;
    while(k--){
        cin>>x; // x个数据 
        s = new double[x];
        w = new double[x];  
        double l = 1000000, r = -1000000;
        for(int i=0;i<x;i++){
            cin>>s[i]>>w[i];
            r = max(s[i], r); // r 是坐标轴上的最小值 
            l = min(s[i], l); // l 是坐标轴上的最大值 
        }
        while(r-l>0.000001){
            double x1 = l + (r-l)/3; // x1取 [l, r]区间的1/3 点 
            double x2 = r - (r-l)/3; // x2取 [l, r]区间的2/3 点 
            if(F(x1) > F(x2)) l = x1; // 若x1点的情绪之和较大, 则x1替换l 
            else r= x2;
        }   
        cout<<"Case #"<<n-k<<": "<< ll(F(l) + 0.5)<<endl;
    } 
    delete []s;
    delete []w;
    return 0;
} 

问题 J: algorithm-跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

输入

多组测试样例。每组测试样例包含一个整数n。(1<=n<=100)

输出

每组测试样例输出一行,表示青蛙跳上n级台阶的跳法数量.

所得到的结果模1000000007

样例输入 Copy)

3
4

样例输出 Copy)

3
5
#include <iostream>
using namespace std;
int res[100];
int tmp = 1000000007;
int Max = 2;
int dp(int n){
    if(n <= Max){
        return res[n];
    }
    else{   
        res[n] = (dp(n-1) + dp(n-2))%tmp; // (a+b)%c = (a%c + b%c)%c
        Max = n;
    }
    return res[n];
} 
int main(){
    int n;
    res[0] = 0;
    res[1] = 1;
    res[2] = 2;
    while(cin>>n){
        cout<<dp(n)<<endl;
    }
    return 0;
} 
​

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值