问题1:活动安排问题
问题描述:
现在给你一个会场,有许社团需要在这个会场上活动,
已知各个社团在这个会场上活动的时间(起始时间和终止时间)
要求出来怎么安排
能够使得这个教室z在这一天之内接待尽可能多的社团
-
解题思路与算法思想
已经知道我们有n个活动需要安排 不妨考虑我们需要首先安排哪个活动 如果这n个活动的开始时间分别为a1-an 结束时间分别为b1-bn 那么对于我们要安排的第一个活动而言(假设这个活动是第i个) 无论他的开始时间是多少 **他占用的时间都是bi** 这是由于虽然她只占用了ai-bi的时间 但是其实第一个活动,那么从0 - ai时间段里注定没有活动 在选取好了第一个活动之后 我们需要选取第二个活动 那么通过将和第一次活动重合的全部活动去掉的方式
我们可以将这个问题转化成选取第一个活动的问题
-
程序模型的建
-
那么可以通过各个社团的结束时间对各个社团进行排序
-
使得结束时间最早的以一些社团位于最前面
-利用贪心的思想每一都选取结束时间最靠前的哪一个 同时去除其他与这个被选择社团时间冲突的社团 再进行下一次比较
-
数据结构的选用
-
利用数组去储存各个社团的开始和终止时间
-
程序设计流程
-
输入数据
-
进行排序
-
得到结果
-
程序设计伪码算法
get things stored in a sort a while(i<a,size()) { if(现在第第一位的开始时间等于大于上一个被选中社团的终止时间) { 计数器+1 ; } i++ ; }
源程序编码清单
#include<iostream>
#include<utility>
#include<vector>
#include<algorithm>
using namespace std ;
bool comp(pair<int ,int >a ,pair<int ,int>b) ;
int main(void)
{
vector< pair<int, int> > b ;
int n ;
scanf("%d",&n) ;
b.resize(n) ;
for(int i = 0 ;i<n ;i++)
{
int tem ;
scanf("%d",&tem) ;
b[i].first = tem ;
scanf("%d",&tem) ;
b[i].second = tem ;
}
sort(b.begin(),b.end(),comp) ;
int end ;
end =b[0].second;
int cnt = 1 ;
for(int i = 0 ;i<b.size() ;i++)
{
if(b[i].first >= end)
{
end = b[i].second ;
cnt++ ;
}
}
printf("%d ",cnt) ;
return 0 ;
}
bool comp(pair<int ,int >a ,pair<int ,int>b)
{
if(a.second<b.second)
{
return true ;
}
else
{
return false ;
}
}
-
程序输入、输出
输入: 5 1 2 3 4 5 6 7 8 9 10 输出:5
输入输出文件或程序运行结果截图
-
时间与空间复杂度分析
时间复杂度: nlogn+n
程序使用说明
总结与完善
“0-1 背包问题
- 问题描述
-
有一容积有限的背包(容积为V)
-
现在有n个物品,每个物品都有自己的价值和提及
-
如何知道一个较优的策略,使得能够放进背包里价值之和最大的的物品
解题的思路
先把各个物品的价值密度求出来 价值/体积
之后通过贪新的思路优先那密度最高的,直到装不下为止
程序模型的建立
- 利用贪新的思路
- 每次选择密度大的哪一个
数据结构的选用
- 利用数组进行存储
- 之后在数组中i进行排序
程序设计流程
- 存入数据
- 进行密度计算
- 进行排序
- 进行贪心
程序设计伪码算法
get a sorted
while(容量小于选择所有物品的体积值之和)
选择价值密度最大的哪一个
源程序编码清单
#include<iostream>
#include<vector>
#include<utility>
#include<algorithm>
using namespace std ;
bool comp(pair<int ,double> a , pair<int ,double> b ) ;
int main(void)
{
int n ;
scanf("%d",&n) ;
int content ;
scanf("%d",&content) ;
vector< pair<int , double> > a ;
a.resize(n) ;
int tem ;
for(vector< pair<int ,double> >::iterator it = a.begin() ; it !=a.end() ;it++ )
{
scanf("%d",&tem) ;
(*it).first = tem ;// capibility it cost ;
scanf("%d",&tem) ;
(*it).second = tem ;//srcond if value ;
(*it).second = (*it).second/(*it).first ;//the ρof things ;
}
sort(a.begin(),a.end(),comp) ;
int cnt = 0 ;
for(vector< pair<int ,double> > :: iterator it = a.begin() ;it != a.end() ;it++)
{
if(cnt+ (*it).first <= content)
{
printf("%d %f\n", (*it).first ,(*it).second) ;
}
cnt+=(*it).first ;
}
}
bool comp(pair<int ,double> a , pair<int ,double> b )
{
if(a.second > b.second)
{
return true ;
}
else
{
return false ;
}
}
程序输入、输出
输入
7 80
10 7
20 8
30 9
40 12
4 7
14 6
5 7
输出
4
5
10
14
20
输入输出文件或程序运行结果截图
时间与空间复杂度分析
- 时间复杂度:n
程序使用说明
总结与完善
“多机调度问题
问题描述
给了你n台机器,m个物品需要加工
每一个物件加工花费的时间是bi ;
我们需要寻找到一个方案,使得这个加工的总时间较短
解题思路与算法思想
- 很原始的贪心模型
- 从最长的时间开始贪心
由于耗时最长的物件需要连续加工很长时间
所以最基本的想法就是先让机器加工最长耗时的物件
为了防止所有其他机器都在等待一个机器的情况
程序模型的建立
- 通过对物品的加工好是的排序
- 之后让已分配加工时间最短的机器加工当时耗时最长的物品
数据结构的选用
- 选数组储存时间
程序设计流程
- 读入数据
- 数据排序
- 物件分配
程序设计伪码算法
sort(所有需要的时间)
while(所有物品没有别分配完)
{
find(现在被分配任务最少的机器)
把这个机器分配上未加工物件中需要耗时最长的
}
源程序编码清单
#include<iostream>
#include<stdio.h>
#include<vector>
#include<utility>
#include<algorithm>
using namespace std ;
bool comp(pair<int ,int>a ,pair<int ,int> b) ;
int main(void)
{
int n ;
scanf("%d",&n ) ;
int m ;
scanf("%d",&m) ;
if(n>=m)
{
vector<int>b ;
int tem_int ;
for(int i = 0 ;i<m ;i++)
{
scanf("%d",&tem_int) ;
b.push_back(tem_int) ;
}
sort(b.begin(),b.end()) ;
printf("%d",b.back()) ;//can be used like this
return 0 ;
}
else
{
vector<pair<int ,int > > b ;
int tem_int ;
pair<int ,int >tem_pair ;
for(int i = 0 ;i<m ;i++)
{
scanf("%d",&tem_int) ;
tem_pair = make_pair(i,tem_int) ;
b.push_back(tem_pair) ;
}
sort(b.begin(),b.end(),comp) ;
vector<int> time ;
for(int i = 0 ; i<n ;i++)
{
time.push_back(0) ;
}
//已经排好序了???????????????????????????????
//怎么贪心???????????????????
int cnt = 0 ;
for(int i = 0 ;i<m ;i++)
{
vector<int>::iterator it = min_element(time.begin(),time.end()) ;
(*it) = (*it)+b[i].second ;
}
printf("%d",*max_element(time.begin(),time.end())) ;
}
}
bool comp(pair<int ,int>a ,pair<int ,int> b)
{
if(a.second>b.second)
{
return true ;
}
else
{
return false ;
}
}
程序输入、输出
输入:
3 10
1 2 3 4 5 6 7 8 9 10
输出
19
输入输出文件或程序运行结果截图
时间与空间复杂度分析
- 时间复杂度:nlogn+n
程序使用说明
总结与完善
“01”子序列问题
问题描述
给定 n 个二进制字符串,要求调整字符串顺序并连接所有的字符
串,使最后得到的字符串中有尽可能多的“01”子序列。输出“01”子序
列的最大个数。 (1 ≤ n ≤ 100000)。
解题思路与算法思想
如果用贪心的思路来解这道题,那么就涉及到一个贪心策略问题
这里我们不妨把一个子串的含1量作为其唯一的评判标准
那么其评判标准的计算公式为 这个子串中1的数量/这个子串符号总数
程序模型的建立
- 利用贪心模型
- 每次都选取数量最大的放到最前面
数据结构的选用
- 利用数组中储存
程序设计流程
- 输入
- 计算密度
- 排序
- 贪心
程序设计伪码算法
for(all the string)
{
a,push_back(1的密度) ;
}
sort(a) ;
while(还有字符串没有被选择)
{
把当面位置的这个字符串放到最后面
}
源程序编码清单
#include<iostream>
#include<stdio.h>
#include<utility>
#include<vector>
#include<algorithm>
using namespace std ;
bool comp(pair<int ,double> a ,pair<int ,double> b) ;
int main(void)
{
vector<string>a ;
int n ;
scanf("%d",&n) ;
string tem ;
for(int i = 0 ;i<n ;i++)
{
cin>>tem ;
a.push_back(tem) ;
}
vector<pair<int ,double> > b ;
for(int i = 0 ;i<n ;i++)
{
double sum = 0 ;
for(int j = 0 ;j<a[i].size() ;j++)
{
sum += (a[i][j]-48) ;
}
sum = sum/(double)a[i].size() ;
pair<int ,double > tempair = make_pair(i,sum) ;
b.push_back(tempair) ;
}
sort(b.begin(),b.end(),comp) ;
for(int i = 0 ;i<b.size() ;i++)
{
cout<<a[b[i].first] ;
}
}
bool comp(pair<int ,double> a ,pair<int ,double> b)
{
if(a.second>b.second)
{
return true ;
}
else
{
return false ;
}
}
程序输入、输出输入
输入:
5
1111
1101
0011
1000
输出:
1111110101100111000
输入输出文件或程序运行结果截图
时间与空间复杂度分析
- 时间复杂度(n*M) ;
程序使用说明
总结与完善
均分纸牌问题
问题描述
有 N 堆纸牌,编号分别为 1,2,…,N。每堆上有若干张,
但纸牌总数必为 N 的倍数。可以在任一堆上取若干张纸牌,
然后移动。
移牌规则为:在编号为 1 的堆上取的纸牌,
只能移到编号为 2 的堆上;
在编号为 N 的堆上取的纸牌
只能移到编号为 N-1 的堆上;
其他堆上取的纸牌,
可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,
用最少的移动次数使每堆上纸牌数都一样多。
解题思路与算法思想
- 我们遇到的首要问题就是如何解决重复交换问题
- 解决方案是我们以从左往右或者从右往左的顺序,每一次都将这个排队移动到最终结果一应该成为的状态
不妨设某一个堆的数量为a,而均分之后的数量为b
并且我们从左向右遍历
如果a=b ,不做操作,次数+0
如果a>b,那么将a-b张纸牌移动到右边的相邻堆上,次数+a-b
如果a<b ,那么把b-a个东西从右边相邻的堆上移动过来 次数+b-a
程序模型的建立
图上一条所描述
要注意的一点为第三种情况下
如果右边相邻的地方数量<b-a
那么我们就把右边的个数记为负数就可以了
数据结构的选用
- 利用数组储存
程序设计流程
- 输入
- 遍历
- 遍历的同时移动+计数
程序设计伪码算法
for(所有的排队)
{
如果a=b ,不做操作,次数+0
如果a>b,那么将a-b张纸牌移动到右边的相邻堆上,次数+a-b
如果a<b ,那么把b-a个东西从右边相邻的堆上移动过来 次数+b-a
}
源程序编码清单
#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std ;
int main(void)
{
int n ;
scanf("%d",&n) ;
vector<int> a ;
int tem ;
int sum = 0 ;
for(int i = 0 ;i<n ; i++)
{
scanf("%d",&tem) ;
a.push_back(tem) ;
sum += tem ;
}
sum = sum/n ;
for(int i = 0 ;i<a.size() ;i++)
{
a[i]-=sum ;
}
int action = 0 ;
for(int i = 0 ;i<a.size() ;i++)
{
if(a[i]<0)
{
action++ ;
a[i+1] += a[i] ;
}
if(a[i]>0)
{
action ++;
a[i+1] += a[i] ;
}
}
printf("%d",action) ;
}
程序输入、输出
输入:
5
1 2 3 4 10
输出
20
输入输出文件或程序运行结果截图
时间与空间复杂度分析
程序使用说明
总结与完善