4-1 会场安排问题
【问题描述】假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。设计一个有效的贪心算法进行安排。(这个问题实际上是著名的图着色问题。若将每个活动作为图的一个顶点,不相容活动用边相连。使相邻顶点着有不同颜色的最小着色数,相当于要找的最小会场数。)
【算法设计】对于给定的k个待安排的活动,计算使用最少会场的时间表。
【数据输入】由文件input.txt给出输入数据。第1行有1个正整数k,表示有k个待安排的活动。接下来的k行中,每行有2个正整数,分别表示k个待安排的活动的开始时间和结束时间。时间以0点开始的分钟计。
【结果输出】将计算的最少会场数输出到文件output.txt。
代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
using namespace std;
int main()
{
// 打开输入输出文件
ifstream inFile("input.txt"); // 记得在当前目录创建input.txt并且将数据保存进去
ofstream outFile("output.txt");
int n;
vector<int> s; // 存储活动开始时间
vector<int> f; // 存储活动结束时间,也即会场空闲时间
int i,j;
int ans;
inFile>>n;
s.resize(n+1); // 调整vector大小以存储n个活动
f.resize(n+1);
for(int i=1;i<=n;i++)
{
inFile>>s[i]>>f[i];
}
// 按非递减顺序排序开始时间和结束时间
sort(s.begin()+1, s.end());
sort(f.begin()+1, f.end());
j=1; // 初始化:会场最早空闲时间即最早活动结束时间
ans=1; // 初始化:第一个活动必须分配一个新会场
// 遍历剩下的活动
for(int i=2;i<=n;i++)
{
// 检查当前最早结束的会场是否可以容纳新的活动
if (f[j]>s[i])
{
ans++; // 需要新开一个会场
}
else
{
j++; // 当前活动更新为在此会场结束
}
}
outFile<<ans<<endl;
inFile.close();
outFile.close();
return 0;
}
// 运行完成后打开output.txt文件即可看到结果
4-7 多处优服务次序问题
【问题描述】有n个顾客同时等待一项服务。顾客i要的服务时间为ti(1≤i≤n),共有s处可以提供此项服务。应如何安排n个顾客的服务次序,才能使平均等待时间达到最小?平均等待时间是n个顾客等待服务时间的总和除以n。
【算法设计】对于给定的n个顾客需要的服务时间和s的值,计算最优服务次序。
【数据输入】由文件input.txt给出输入数据。第1行有2个正整数n和s,表示有n个顾客且有s处可以提供顾客需要的服务。接下来的1行中有n个正整数,表示n个顾客需要的服务时间。
【结果输出】将计算的最小平均等待时间输出到文件output.txt。
代码如下:
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
ifstream inputFile("input.txt");
ofstream outputFile("output.txt");
int n, s;
inputFile>>n>>s;
vector<int> serviceTimes(n);
for (int i=0;i<n;i++) {
inputFile>>serviceTimes[i];
}
// 按升序排序服务时间以获得最小等待时间
sort(serviceTimes.begin(),serviceTimes.end());
// 计算最小平均等待时间
vector<int> serviceStations(s,0); // 初始化s个服务处,每个服务处的初始时间为0
long long totalWaitTime=0;
for(int i=0;i<n;i++){
// 将当前顾客安排到最早空闲的服务处
sort(serviceStations.begin(), serviceStations.end());
totalWaitTime+=serviceStations[0]; // 当前顾客的等待时间等于服务处的完成时间
serviceStations[0]+=serviceTimes[i]; // 更新服务处的完成时间
}
totalWaitTime=totalWaitTime+serviceStations[0]+serviceStations[1]; // 加上等待最后两位的时间
// 计算平均等待时间
double averageWaitTime=static_cast<double>(totalWaitTime)/n;
outputFile<<averageWaitTime<<endl;
inputFile.close();
outputFile.close();
cout<<"计算完成,结果已写入output.txt"<<endl;
return 0;
}
// 运行完成后打开output.txt文件即可看到结果
4-15 最优分解问题
【问题描述】设n是一个正整数。现在要求将n分解为若干互不相同的自然数的和,且使这些自然数的乘积最大。
【算法设计】对于给定的正整数n,计算最优分解方案。
【数据输入】由文件input.txt提供输入数据。文件的第1行是正整数n。
【结果输出】将计算的最大乘积输出到文件output.txt。
代码如下:
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
ifstream inputFile("input.txt");
ofstream outputFile("output.txt");
int n;
inputFile>>n;
inputFile.close();
long long maxProduct=1;
// 正整数1~4情况较为特殊,单独处理
if(n==1){ // 1=0+1
maxProduct=0;
outputFile<<maxProduct<<endl;
outputFile.close();
return 0;
}
if(n==2){ // 2=0+2
maxProduct=0;
outputFile<<maxProduct<<endl;
outputFile.close();
return 0;
}
if(n==3){ // 3=1+2
maxProduct=2;
outputFile<<maxProduct<<endl;
outputFile.close();
return 0;
}
if(n==4){ // 4=1+3
maxProduct=3;
outputFile<<maxProduct<<endl;
outputFile.close();
return 0;
}
vector<int> parts;
int sum=0;
int nextNum=2;
// 不断增加互不相同的自然数,直到总和接近 n
// 贪心地选择最小的自然数2, 3,...(除1以外),这样保证乘积尽量大
while(sum+nextNum<=n){
parts.push_back(nextNum);
sum+=nextNum;
nextNum++;
}
// 如果总和小于n,将剩余部分均匀地分给前面各项
int remainder=n-sum;
int index=parts.size()-1;
while(remainder>0){
parts[index]++;
remainder--;
index--;
if(index<0){
index=parts.size()-1; // 回到最后一个元素,继续均匀分配
}
}
// 计算这些数的乘积
// 乘积最大化的原因是:分解成接近相等的因子时,乘积达到最大
for (int num:parts){
maxProduct*=num;
}
outputFile<<maxProduct<<endl;
outputFile.close();
cout<<"计算完成,结果已写入output.txt"<<endl;
return 0;
}
// 运行完成后打开output.txt文件即可看到结果