作业二三 实验一二三

1.山东建筑大学烟台校区启用,现需要为n位同学分配宿舍,假设学校充分尊重同学们的意见,即可以任何x个同学使用一间宿舍(x>0),问:一共有多少种宿舍分配方案?

#include<bits/stdc++.h>

#include <stdio.h>

using namespace std;

long long int f(int n,int m ){

       if(n > 0 && m == 0 ||n == 0&& m > 0){

              return 0;

       }

    

        else if(n == m)    {

           return 1;

       }

    else{

           return f(n-1 ,m-1) + m*f(n-1 ,m);

       }     

       }

int main(){

       int n ,m;

       cin>> n;

       long long int a[101] = {};

       long long int sum = 0;

    for(int i = 1;i<=n; i++){

           a[i] = f(n ,i);

           sum += a[i];

  }

  cout <<sum<<endl;

  return 0;

}

2.考虑下面的应用场景: 山东建筑大学烟台校区启用,现需要为n位同学分配至m间宿舍,问:一共有多少种宿舍分配方案?

#include <bits/stdc++.h>

#include <iostream>

#include <vector>

using namespace std;

int countAllocation(int n, int m) {

    vector<vector<int>> dp(n+1, vector<int>(m+1, 0));

    for (int i = 1; i <= n; i++) {

        for (int j = 1; j <= m; j++) {

            if (i == j || j == 1) {

                dp[i][j] = 1;

            } else {

                dp[i][j] = j * dp[i-1][j] + dp[i-1][j-1];

            }

        }

    }

    return dp[n][m];

}

int main() {

    int n, m;

    cin >> n >> m;

    int result = countAllocation(n, m);

    cout << result << endl;

    return 0;

}

3.给定一串十进制数字,共n位,要求将这些数字分成m段,由此得到了m个整数。如何划分使得m个整数的乘积最大?

#include <iostream>

#include <vector>

using namespace std;

int main() {

    int n, p;

    cin >> n >> p;

    string digits;

    cin >> digits;

    vector<vector<int>> dp(n + 1, vector<int>(p + 1, 0));

    for (int i = 1; i <= n; i++) {

        dp[i][1] = dp[i - 1][1] * 10 + (digits[i - 1] - '0');

    }

    for (int i = 2; i <= n; i++) {

        for (int j = 2; j <= p; j++) {

            int maxProduct = 0;

            for (int k = i - 1; k >= j - 1; k--) {

                int currentSegment = stoi(digits.substr(k, i - k));

                maxProduct = max(maxProduct, dp[k][j - 1] * currentSegment);

            }

            dp[i][j] = maxProduct;

        }

    }

    cout << dp[n][p] << endl;

    return 0;

}

4.现有一个二维的金字塔,由若干方格组成,每个方格里的数字表明该方格的宝物价值。 你可以选择一条从塔顶到塔底的路线(每层只能走一个方格,该方格必须为上一层走过方格的相邻方格),并收集路线上所有方格的宝物,如何选择路线,使得最终收集到的宝物价值的和最大? '

#include <bits/stdc++.h>

#include <iostream>

#include <vector>

using namespace std;

int main() { 

    int n;

    cin >> n;

   

    vector<vector<int>> a(n, vector<int>(n, 0));

    for (int i = 0; i < n; ++i) {

        for (int j = 0; j <= i; ++j) {

            cin >> a[i][j];

        }

    }

   

 

    for (int i = n - 2; i >= 0; --i) {

        for (int j = 0; j <= i; ++j) {

            a[i][j] += max(a[i + 1][j], a[i + 1][j + 1]);

        }

    }

    int max_value = a[0][0];

   

    cout << max_value << endl;

   

    return 0;

}

5. 磁带最优存储问题要求确定这 n 个程序在磁带上的一个存储次序,使平均读取时间达到最小。试设计一个解此问题的算法,并分析算法的正确性和计算复杂性。

#include <bits/stdc++.h>

using namespace std;

int n;

struct node {

  int a, b;

}

p[10000];

bool cmp(node a, node b) {

  return a.a * a.b < b.a * b.b;

}

int main() {

  cin >> n;

  int sum = 0;

  for (int i = 0; i < n; i++) {

    cin >> p[i].a >> p[i].b;

    sum += p[i].b;

  }

  sort(p, p + n, cmp);

  double t = 0, tmp = 0;

  for (int i = 0; i < n; i++) {

    tmp = 0;

    for (int j = 0; j <= i; j++) {

      tmp += p[j].a * (p[j].b * 1.0 / sum);

    }

    t += tmp;

  }

  printf("%.6g\n", t);

  return 0;

}

6. 山东建筑大学有足够多的教室,可以安排一学期内的所有课程。当然,教务处希望使用的教室数量越少越好。设计一个有效的贪心算法进行排课。

#include <bits/stdc++.h>

using namespace std;

struct Course {

    int start_time;

    int end_time;

};

bool compareCourses(const Course& c1, const Course& c2) {

    return c1.start_time < c2.start_time;

}

int findMinClassrooms(vector<Course>& courses) {

    sort(courses.begin(), courses.end(), compareCourses);

   

    vector<int> end_times;

    end_times.push_back(courses[0].end_time);

   

    for (int i = 1; i < courses.size(); i++) {

        bool assigned = false;

        for (int j = 0; j < end_times.size(); j++) {

            if (courses[i].start_time >= end_times[j]) {

                end_times[j] = courses[i].end_time;

                assigned = true;

                break;

            }

        }

        if (!assigned) {

            end_times.push_back(courses[i].end_time);

        }

    }

   

    return end_times.size();

}

int main() {

    int n;

    cin >> n;

   

    vector<Course> courses(n);

    for (int i = 0; i < n; i++) {

        cin >> courses[i].start_time >> courses[i].end_time;

    }

   

    int min_classrooms = findMinClassrooms(courses);

    cout << min_classrooms << endl;

   

    return 0;

}

实验2.1:假设从济南到西藏的路线上共有n个城市1,2,…,n,每个城市都有一个租车公司。你可以在这些城市出租汽车,并在之后的任何一个城市归还汽车。城市i到城市j之间的租金为x(i,j),1≤i<j≤n。试设计一个算法,计算从济南(城市1)到西藏(城市n)所需的最少租金。

#include <iostream>

#include <vector>

#include <climits>

using namespace std;

int main(){

    int n;

    cin>>n;

    vector<vector<int>>f(n+1,vector<int>(n+1,0));

    vector<int>c(n+1,INT_MAX);

    for(int i=1;i<=n;i++){

        for(int j=i+1;j<=n;j++){

            cin>>f[i][j];

        }

    }

    c[1]=0;

    for(int i=2;i<=n;i++){

        c[i]=INT_MAX;

        for(int j=1;j<i;j++){

            c[i]=min(c[i],c[j]+f[j][i]);

        }

    }

    cout<<c[n]<<endl;

    return 0;

}

实验2.2:云天明送给程心一串珍贵的项链,上面共有n颗珍珠,每一颗珍珠上都有一个数字。

每两颗相邻的珍珠可以合并为一颗新的珍珠,合并后这两颗珍珠消失,新珍珠上的数字为合并的两颗的的数字之和。并且此次操作的得分要加上这个和。

经过n-1次这样的合并后,项链只剩下最后一颗珍珠,问总得分的最小值和最大值。

#include <bits/stdc++.h>

#define INF 0x3f3f3f3f

using namespace std;

const int MAXN = 205;

int pearl[MAXN], sum[MAXN];

int minpearl[MAXN][MAXN], maxpearl[MAXN][MAXN];

int main() {

    int n;

    cin >> n;

    for (int i = 1; i <= n; i++) {

        cin >> pearl[i];

        pearl[i + n] = pearl[i];

    }

   

    for (int i = 1; i <= 2 * n; i++) {

        sum[i] = sum[i - 1] + pearl[i];

}

    for (int len = 2; len <= n; len++) {

        for (int i = 1; i <= 2 * n - len + 1; i++) {

            int j = i + len - 1;

            minpearl[i][j] = INF;

            maxpearl[i][j] = 0;

            for (int k = i; k < j; k++) {

                minpearl[i][j] = min(minpearl[i][j], minpearl[i][k] + minpearl[k + 1][j] + sum[j] - sum[i - 1]);

                maxpearl[i][j] = max(maxpearl[i][j], maxpearl[i][k] + maxpearl[k + 1][j] + sum[j] - sum[i - 1]);

            }

        }

}

    int Max = 0, Min = INF;

    for (int i = 1; i <= n; i++) {

        int j = i + n - 1;

        Max = max(Max, maxpearl[i][j]);

        Min = min(Min, minpearl[i][j]);

    }

    cout << Min << endl << Max << endl;

}

实验2.3:对于长度相同的 2 个字符串 A 和 B,其距离定义为相应位置字符距离之和。2 个非空格字符的距离是它们的 ASCII 码之差的绝对值。空格与空格的距离为 0;空格与其它字符的距离为一定值 k。 在一般情况下,字符串 A 和 B 的长度不一定相同。字符串 A 的扩展是在 A 中插入若干空格字符所产生的字符串。在字符串 A 和 B 的所有长度相同的扩展中,有一对距离最小的扩展,该距离称为字符串 A 和 B 的扩展距离。 对于给定的字符串 A 和 B,试设计一个算法,计算其扩展距离。

#include <bits/stdc++.h>

using namespace std;

int dist(char c1, char c2, int k) {

    return (c1 == ' ' || c2 == ' ') ? k : abs(c1 - c2);

}

int main() {

    string a, b;

    cin >> a >> b;

    int t;

    cin >> t;

    int len1 = a.size();

    int len2 = b.size();

    vector<vector<int> > c(len1 + 1, vector<int>(len2 + 1, 0));

    for (int i = 1; i <= len1; i++) {

        c[i][0] = t * i;

    }

    for (int i = 1; i <= len2; i++) {

        c[0][i] = t * i;

    }

    for (int i = 1; i <= len1; i++) {

        for (int j = 1; j <= len2; j++) {

            c[i][j] = min(c[i - 1][j - 1] + dist(a[i - 1], b[j - 1], t),

                           min(c[i - 1][j] + t, c[i][j - 1] + t));

        }

    }

    cout << c[len1][len2] << endl;

    return 0;

}

实验2.4:现有一对双胞胎,在一个有n * n个方格的方形宝藏区域F中探宝。(i,j)方格中宝物的价值为v(i,j),如下图所示。

双胞胎均从F的A点出发,向下或向右行走,直到B点,在走过的路上,收集方格中的宝藏。试找出兄弟二人可以获得的宝藏总价的值最大。

#include <iostream>

using namespace std;

const int MAX_N = 101;

int a[MAX_N][MAX_N];

int m[MAX_N][MAX_N][MAX_N][MAX_N];

int n;

int max(int a, int b) {

    return (a > b) ? a : b;

}

void f(int x1, int y1, int x2, int y2, int t) {

    if (x1 == x2 && y1 == y2) {

        m[x1][y1][x2][y2] = max(m[x1][y1][x2][y2], t + a[x1][y1]);

    } else {

        m[x1][y1][x2][y2] = max(m[x1][y1][x2][y2], t + a[x1][y1] + a[x2][y2]);

    }

}

void GetList() {

    int x1, y1, x2, y2;

    m[1][1][1][1] = a[1][1];

    int s;

    for (s = 2; s <= 2 * n - 1; s++) {

        for (x1 = 1; x1 <= s - 1; x1++) {

            for (x2 = 1; x2 <= s - 1; x2++) {

                y1 = s - x1;

                y2 = s - x2;

                int t = m[x1][y1][x2][y2];

                f(x1 + 1, y1, x2 + 1, y2, t);

                f(x1 + 1, y1, x2, y2 + 1, t);

                f(x1, y1 + 1, x2 + 1, y2, t);

                f(x1, y1 + 1, x2, y2 + 1, t);

            }

        }

    }

}

int main() {

    cin >> n;

    int x, y, v;

    while (cin >> x >> y >> v && (x || y || v)) {

        a[x][y] = v;

    }

    GetList();

    cout << m[n][n][n][n] << endl;

    return 0;

}

实验2.5:有兄弟二人做n道题目。

已知哥哥做题目i需要时间ai,弟弟做题目i需要时间bi 。

由于兄弟二人对知识掌握的程度不同,很可能对于某些 i,有 ai ≥ bi ,而对于某些 j,j≠i,有 aj < bj 。

每一道题目只能交给二人中的一个来做。

设计一个算法,使得二人解掉所有题目所用的时间最短(从任何一人开始做题到最后一人解掉最后一道题目的总时间)。

研究一个实例: (a1,a2,a3,a4,a5,a6)=(2,5,7,10,5,2);(b1,b2,b3,b4,b5,b6)=(3,8,4,11,3,4)。

#include <iostream>

using namespace std;

const int MAX_N = 1000;

const int MAX_TIME = 10000;

int n;

int aT = 0;

int mintime = MAX_TIME;

int a[MAX_N];

int b[MAX_N];

int c[MAX_N][MAX_TIME];

int T() {

    for (int i = 0; i <= n; i++) {

        for (int j = 0; j <= aT; j++) {

            c[i][j] = MAX_TIME;

        }

    }

    c[0][0] = 0;

    for (int i = 1; i <= n; i++) {

        for (int j = 0; j <= aT; j++) {

            c[i][j] = c[i - 1][j] + b[i];

            if (j >= a[i]) {

                c[i][j] = min(c[i][j], c[i - 1][j - a[i]]);

            }

        }

    }

    for (int j = 0; j <= aT; j++) {

        int t = max(c[n][j], j);

        mintime = min(mintime, t);

    }

    return mintime;

}

int main() {

    cin >> n;

    for (int i = 1; i <= n; i++) {

        cin >> a[i];

        aT += a[i];

    }

    for (int i = 1; i <= n; i++) {

        cin >> b[i];

    }

    T();

    cout << mintime << endl;

    return 0;

}

实验2.6作为一个比赛队伍总教练的你,请解决下面的问题:

你作为总教练的聘期为n天。

在这n天里,一共有n个比赛可以参加。

队员们都愿意参加比赛,而不愿意训练,所以希望有比赛就参加。

如果在某一天有多场比赛同时开始,作为主教练的你可任选其中一场比赛参加(前提是队伍没有正在参加的比赛)。

比赛从第s天开始,持续t天,则该比赛在第 s+t-1 天结束。

作为总教练的你,应该如何选择比赛,才能既使得队员满意

#include <bits/stdc++.h>

using namespace std;

vector<int> a, b, c;

int main() {

    int n, x;

    cin >> n >> x;

    a.resize(n + 2, INT_MAX);

    b.resize(x + 1);

    c.resize(x + 1);

    for (int i = 1; i <= x; i++) {

        int y, t;

        cin >> y >> t;

        b[i] = y;

        c[i] = t;

    }

    int m = 0;

    for (int i = n; i >= 1; i--) {

        a[n + 1] = n;

        for (int j = 1; j <= x; j++) {

            if (b[j] == i) {

                a[i] = min(a[b[j] + c[j]], a[i]);

                m += 1;

            }

        }

        if (m == 0) {

            a[i] = a[i + 1] - 1;

        }

        m = 0;

    }

    cout << a[1];

    return 0;

}

1.1大于 1 的正整数 n 可以分解为:n=x1x2…*xm。对于给定的正整数 n,编程计算 n 共有多少种不同的分解式。

#include <bits/stdc++.h>

using namespace std;

map<int ,int >a;

int f(int n){

    if(n == 1)

        return 1;

    if(a[n])

        return a[n];

    int curCount=1;

    for(int i=2;i<=sqrt(n);i++){

        if(n%i == 0){

            curCount+=f(i);

           

            if(i!=n/i){

                curCount+=f(n/i);

            }

        }

    }

    a[n] = curCount;

    return a[n];

}

int main()

{

    int n;

    while(cin>>n){

        cout<<f(n)<<endl;

    }

}

1.2设 A、B、C 是 3 个塔座。开始时,在塔座 A 上有一叠共 n 个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为 1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座 A 上的这一叠圆盘移到塔座 B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则: 规则(1):每次只能移动 1 个圆盘; 规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上; 规则(3):任何时刻都不允许将同色圆盘叠在一起; 规则(4):在满足移动规则(1)-(3)的前提下,可将圆盘移至 A,B,C 中任一塔座上。 试设计一个算法,用最少的移动次数将塔座 A 上的 n 个圆盘移到塔座 B 上,并仍按同样顺序叠置。

#include <bits/stdc++.h>

#include<iostream>

using namespace std;

void Hannoi(int,char,char,char);

int main()

{

       int n;

       cin>>n;

       Hannoi(n,'A','B','C');

       return 0;

}

void Move(int i,char M,char N)

{  

       cout<<i<<' '<<M<<' '<<N<<endl; 

}

void Hannoi(int n,char W1,char W2,char W3)

{

       if(n==1)

       {

              Move(1,W1,W2);

              return;

       }

       n--;

       Hannoi(n,W1,W3,W2);

       Move(n+1,W1,W2);

       Hannoi(n,W3,W2,W1);

}

1.3给定一个自然数 n,由 n 开始可以依次产生半数集 set(n)中的数如下。 (1) n∈set(n); (2) 在 n 的左边加上一个自然数,但该自然数不能超过最近添加的数的一半; (3) 按此规则进行处理,直到不能再添加自然数为止。 例如,set(6)={6,16,26,126,36,136}。半数集 set(6)中有 6 个元素。 注意半数集是多重集#include <bits/stdc++.h>

using namespace std;

vector<int> a;

int comp(int n)

{

    if (n == 0) {

        return 0;

    }

    if (a[n] > 0) {

        return a[n];

    }

    int ans = 1;

    for (int i = 1; i <= n / 2; i++) {

        ans += comp(i);

    }

    a[n] = ans;

    return ans;

}

int main()

{

    int n;

    while (cin >> n && n != 0) {

        a.resize(n + 1, 0);

        a[1] = 1;

        cout << comp(n) << endl;

    }

    return 0;

}。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值