作业2.1:考虑下面的应用场景: 山东建筑大学烟台校区启用,现需要为n位同学分配宿舍,假设学校充分尊重同学们的意见,即可以任何x个同学使用一间宿舍(x>0),问:一共有多少种宿舍分配方案?
#include <iostream>
using namespace std;
long f(int n,int m)
{
if(m==1||m==n)
{
return 1;
}
else{
return f(n-1,m-1)+m*f(n-1,m);
}
}
int main()
{
int n,m;
long long sum=0;
cin>>n;
for(int m=1 ; m<=n; m++){
long count=f(n,m);
sum=sum+count;
}
cout<<sum<<endl;
return 0;
}
作业2.2:考虑下面的应用场景: 山东建筑大学烟台校区启用,现需要为n位同学分配至m间宿舍,问:一共有多少种宿舍分配方案?
#include <iostream>
using namespace std;
int f(int n,int m)
{
if(m==1||m==n)
{
return 1;
}
else{
return f(n-1,m-1)+m*f(n-1,m);
}
}
int main()
{
int n,m;
cin>>n>>m;
cout<<f(n,m)<<endl;
return 0;
}
作业3.1现有一个二维的金字塔,由若干方格组成,每个方格里的数字表明该方格的宝物价值。 你可以选择一条从塔顶到塔底的路线(每层只能走一个方格,该方格必须为上一层走过方格的相邻方格),并收集路线上所有方格的宝物,如何选择路线,使得最终收集到的宝物价值的和最大? '
2
1 2
1 2 1
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n;
cin >> n;
vector<vector<int> >p(n,vector<int>(n,0));
for(int i=0;i<n;++i){
for(int j=0;j<=i;++j){
cin >> p[i][j];
}
}
for(int i=n-2;i>=0;--i){
for(int j=0;j<=i;++j){
p[i][j]+=max(p[i+1][j],p[i+1][j+1]);
}
int max=p[0][0];
cout << max <<endl;
return 0;
}
作业3.2:给定一串十进制数字,共n位,要求将这些数字分成m段,由此得到了m个整数。如何划分使得m个整数的乘积最大?
数据输入:
第 1 行中包含n和m。 第2行是n位十进制整数。(n<=10)
数据输出:
输出最大乘积。
#include<iostream>
using namespace std;
#define N 50
int a[N][N];
char re[N];
int f(char arr[],int i,int j)
{
int sum=0;
while(i<=j)
{
sum = sum*10+arr[i]-'0';
i++;
}
return sum;
}
int main()
{
int n,k,i,j,l,max,flag;
while(cin>>n>>k)
{
for(i=1;i<=n;i++)
cin>>re[i];
a[1][1]=re[1]-'0';
for(i=2;i<=n;i++)
a[i][1]=a[i-1][1]*10+(re[i]-'0');
for(j=2;j<=k;j++)
{
max=-1;
for(i=1;i<=n;i++)
{
if(j>i)
a[i][j]=0;
else
{
for(l=j-1;l<=i-1;l++)
{
flag=a[l][j-1]*f(re,l+1,i);
if(flag>max)
max=flag;
}
a[i][j]=max;
}
}
}
cout<<a[n][k]<<endl;
}
return 0;
}
作业4.1:任务描述
在一条直线上,有n个宝藏,每个宝藏的坐标是ai。其中ai为整数,n <= 10000
传说曹操手下有一批摸金校尉,每个摸金校尉可以收集长度为k的一段距离内的宝藏。比如,如果一个摸金校尉从坐标为x的位置开始收集,他可以收集[x,x+n]范围内的所有宝藏。
现给出n个宝藏的坐标,问至少需要多少摸金校尉才可以收集到所有的宝藏?
输入
第一行为n和k的值,n <= 10000。 接下来一行是n个整数,代表n个宝藏的坐标ai。
输出
输出所需要的最少的摸金校尉的个数。
#include <bits/stdc++.h>
using namespace std;
int main()
{
long n, k;
cin >> n >> k;
long a[n];
for(int i = 0; i < n; ++i)
{
cin >> a[i];
}
sort(a,a+n);
long ans = 1;
long cur = a[0] + k;
for(int i = 1; i < n; ++i)
{
if(a[i] > cur)
{
++ans;
cur = a[i] + k;
}
}
cout << ans << endl;
return 0;
}
作业4.2任务描述
设有 n 个顾客同时等待一项服务。顾客i 需要的服务时间为ti ,1 ≤ i ≤ n 。共有 s 处可以提供此项服务。应如何安排 n 个顾客的服务次序才能使平均等待时间达到最小?平均等待时间是 n 个顾客等待服务时间的总和除以 n。
编程任务:
对于给定的 n 个顾客需要的服务时间和 s 的值,编程计算最优服务次序。
数据输入:
输入数据第一行有 2 个正整数 n 和 s,表示有 n 个顾客且有 s 处可以提供顾客需要的服务。接下来的 1 行中,有 n 个正整数,表示 n 个顾客需要的服务时间。 1 ≤ n ≤ 10000
结果输出:
将计算出的最小平均等待时间输出。
#include <bits/stdc++.h>
using namespace std;
int main()
{
long n, s;
cin >> n >> s;
long a[n];
for(long i = 0; i < n; ++i)
{
cin >> a[i];
}
sort(a, a+n);
long sum = 0;
long t[s] = {0};
for(long i = 0; i < n; ++i)
{
t[i%s] = t[i%s] + a[i];
sum += t[i%s];
}
sort(t, t+s);
double total;
total = sum * 1.0 / n;
cout << total << 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;
}
实验3.1问题描述:
山东建筑大学有足够多的教室,可以安排一学期内的所有课程。当然,教务处希望使用的教室数量越少越好。设计一个有效的贪心算法进行排课。
编程任务:
对于给出的 n 个待排课的课程,编程计算使用最少教室的数量。0 ≤ n ≤ 10000。
数据输入:
输入数据第一行有 1 个正整数 n,表示有 n 个待排课的课程。 接下来的 n 行中,每行有 2 个正整数,分别表示 n 个待排课程的开始时间和结束时间。时间以 0 点开始的分钟计。
结果输出:
输出需要的最少教室数量。
#include <iostream>
#include <algorithm>
using namespace std;
int Minclassroom(pair<int, int>* courses, int n) {
sort(courses, courses + n);// 按开始时间排序
int* endtime = new int[n];// 动态数组来记录每个教室的结束时间
endtime[0] = courses[0].second;// 将第一个课程的结束时间存入endtime数组中
int endtimeCount = 1;// 记录教室数量的变量
for (int i = 1; i < n; i++) {
bool hasRoom = false;
for (int j = 0; j < endtimeCount; j++) {
if (courses[i].first >= endtime[j]) {
endtime[j] = courses[i].second;// 将课程安排到已有教室中
hasRoom = true;
break;
}
}
if (!hasRoom) {
endtime[endtimeCount] = courses[i].second;// 需要额外开设一个教室,并将时间加入到endtime数组中
endtimeCount++;
}
}
delete[] endtime;// 释放动态数组的内存空间
return endtimeCount;// 返回最少教室数量
}
int main() {
int n;
cin >> n;
pair<int, int>* courses = new pair<int, int>[n];// 动态数组来存储课程的开始和结束时间
for (int i = 0; i < n; i++) {
cin >> courses[i].first >> courses[i].second;// 读取课程的开始时间和结束时间
}
int minClassrooms = Minclassroom(courses, n);// 计算最少教室数量
cout << minClassrooms << endl;// 输出最少教室数量
delete[] courses;// 释放动态数组的内存空间
return 0;
}
实验3.2:设有 n 个程序{1,2,…, n }要存放在长度为 L 的磁带上。程序 i 存放在磁带上的长度是li ,1 ≤ i ≤ n 。这 n 个程序的读取概率分别是p1, p2 ,……, pn ,且 ∑pi(i=1~n) = 1。
如果将这 n 个程序按i1,i2 ,……,in 的次序存放,则读取程序ir 所需的时间tr = c*∑pi li (i=1 ~ r)。这 n 个程序的平均读取时间为∑tr (r=1 ~ n)。
磁带最优存储问题要求确定这 n 个程序在磁带上的一个存储次序,使平均读取时间达到最小。试设计一个解此问题的算法,并分析算法的正确性和计算复杂性。
#include<iostream>
#include<queue>
using namespace std;
struct Tape
{
int len;
int pr;
double tr;
friend bool operator< (Tape a,Tape b) { return a.tr > b.tr; }
Tape(int l=0,int p=0):len(l),pr(p),tr(l*p) {}
};
double minTimeCost(priority_queue<Tape>& tape, long long sum)
{
double res = 0, acc = 0;
while (!tape.empty())
{
acc += tape.top().tr / sum;
res += acc;
tape.pop();
}
return res;
}
int main()
{
int n, a, b;
long long sum = 0;
cout << "";
cin >> n;
priority_queue<Tape> tape;
cout << "" << endl;
for (int i = 0; i < n; i++)
{
cin >> a >> b;
tape.push(Tape(a,b));
sum += b;
}
double res = minTimeCost(tape, sum);
cout << "" << res << endl;
return 0;
}
实验4.1问题描述:
95枪族是我国现役主力步枪之一。假设某95步枪由 n 个部件组成,每一种部件都可以从 m 个不同的供应商处购得。设 wij 是从供应商 j 处购得的部件 i 的重量,cij 是相应的价格。 试设计一个算法,给出总价格不超过 c 的最小重量步枪的部分采购方案。
编程任务:
对于给定的步枪部件重量和步枪部件价格,编程计算总价格不超过 d 的最小重量步枪设计。
数据输入:
输入数据第一行有 3 个正整数 n ,m 和 d。接下来的 2n 行,每行 m 个数。前 n 行是 c,后 n 行是 w。 1 <= n, m <= 20。
结果输出:
将计算出的最小重量输入,并输出每个部件的供应商。
#include <iostream>
using namespace std;
int n,m;
int d,cw=0,cp=0,minp=0,minw=0;
int bestw=9999999,x[27],bestx[27],w[27][27],c[27][27],rp[27],rw[27];
bool backtrack(int i){
if(i>n){
bestw=cw;
for(int j=1;j<=n;j++){
bestx[j]=x[j];
}
return true;
}
bool found=false;
for(int j=1;j <= m;j++){
x[i]=j;
cw+=w[i][j];
cp+=c[i][j];
minp-=rp[i];
minw-=rw[i];
if(cw+minw < bestw && cp+minp <= d){
if(backtrack(i+1)){
found=true;
}
}
cp-=c[i][j];
cw-=w[i][j];
minp+=rp[i];
minw+=rw[i];
}
return found;
}
int main(){
cin>>n>>m>>d;
int temp=999999;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c[i][j];
if(c[i][j] < temp) temp=c[i][j];
}
rp[i]=temp;
minp+=rp[i];
temp=999999;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>w[i][j];
if(w[i][j] < temp) temp=w[i][j];
}
rw[i]=temp;
minw+=rw[i];
temp=999999;
}
backtrack(1);
cout<<bestw<<endl;
for(int i=1;i<=n;i++){
cout<<bestx[i]<<" ";
}
return 0;
}