NOIP(三)- 贪心算法
1 #include <iostream>
2 #include <string>
3 #include <cstring>
4 using namespace std;
5 int main(){
6 【例1】排队打水问题
7 有N个人排队到R个水龙头去打水,他们装满水桶的时间为T1,T2,…,Tn为整数且各不相等,
8 应如何安排他们的打水顺序才能使他们花费的时间最少?
9 【算法分析】
10 由于排队时,越靠前面的计算的次数越多,显然越小的排在越前面得出的结果越小
11 (可以用数学方法简单证明,这里就不再赘述),所以这道题可以用贪心法解答,基本步骤:
12 (1)将输入的时间按从小到大排序;
13 (2)将排序后的时间按顺序依次放入每个水龙头的队列中;
14 (3)统计,输出答案。
15 【样例输入】
16 4 2 4人打水,2个水龙头
17 2 6 4 5 每个打水时间
18 参考程序主要框架如下:
19 int n,r,i;
20 int a[101];
21 int s[101];
22 cin>>n>>r;
23 memset(s,0,sizeof(s)); 初始化-将s数组的值全部初始化为0
24 int j=0;
25 int minx=0;
26 for(int k = 0;k < n;k++){
27 cin >> s[k];
28 }
29 for(i=1;i<=n;++i){ 用贪心法求解
30 j++;
31 if (j == r + 1){
32 j=1;
33 } 前r个人为一组,第r+1个人回到第一个水龙
34 s[j] += a[i]; 加上等待时间
35 minx += s[j];
36 }
37 cout << minx; 输出解答
38 return 0;
39 }
1 #include <iostream>
2 #include <cstdio>
3 #include <string>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7 int s[1001],a[1001];
8 int main(){
9 【例1】排队打水问题
10 有N个人排队到R个水龙头去打水,他们装满水桶的时间为T1,T2,…,Tn为整数且各不相等,
11 应如何安排他们的打水顺序才能使他们花费的时间最少?
12 【算法分析】
13 由于排队时,越靠前面的计算的次数越多,显然越小的排在越前面得出的结果越小
14 (可以用数学方法简单证明,这里就不再赘述),所以这道题可以用贪心法解答,基本步骤:
15 (1)将输入的时间按从小到大排序;
16 (2)将排序后的时间按顺序依次放入每个水龙头的队列中;
17 (3)统计,输出答案。
18 【样例输入】
19 4 2 4人打水,2个水龙头
20 2 6 4 5 每个打水时间
21
22 解题的思路:
23 1.从大到小排序
24 2.将排完序的时间按照顺序存入每个水龙头的队列中
25 3.统计
26 从第一个人开始,每个人打水的时间,自己打水的时间+前面的人打水的时间
27 然后,将自己打水的时间用数组保存下来。
28
29 n是总的打水的人,r是水龙头的个数,sum打水时间和
30
31 数模 -- 最优解
32 4 2
33 26 45
34 2 + 8 + 4 + 9 = 23
35 24 56 TCTM@TEDU2018
36 int n,r;
37 cin >> n >> r;
38 存每位同学打水消耗的时间
39 for(int i = 1;i <= n;i++){
40 cin >> a[i];a数组用于存储每位同学打水的时间
41 }
42 sort(a + 1,a + n + 1);
43 int j = 0,minx = 0;
44 用贪心算法求解
45 for(int i = 1;i <= n;++i){
46 j++;记录打水的同学的位置
47 if(j == r + 1){前r个人为一组,第r + 1个人回到第一个水龙头
48 j = 1;
49 }
50 s[j] += a[i];加上等待的时间
51 minx += s[j];
52 }
53 cout << minx;
54 return 0;
55 }
1 #include <iostream>
2 #include <cstdio>
3 #include <string>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7 /**
8 题目:学校里有一个水房,水房里一共装有m个水龙头可供同学们接水,
9 每个水龙头每秒供水量相等,均为1.
10 现有n个同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水
11 顺序从1到n编号,i号同学接水量为wi。
12 接水开始时,1到m号同学各占一个水龙头,并同时打开水龙头接水。
13 当其中某名同学j完成其接水量要求wj后,下一名排队等候接水的同学k马上接替
14 j同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何的水资源浪费。
15 即j同学第x秒结束时完成接水,则k同学第x+1秒立刻开始接水。
16 若当前接水人数n不足m,则只有n个水龙头供水,其他m-n个水龙头依次关闭。
17 现给出n名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒?
18 输入:
19 第一行2个整数n和m,用一个空格隔开,分别表示接水人数和水龙头个数。
20 第二行n个整数w1、w2、......、wn,每两个整数直接用一个空格隔开,wi表示
21 i号同学的接水量。
22 规定1 <= n <= 10000; 1 <= m <= 100 且 m <= n ; 1 <= wi <= 100。
23 输出:
24 输出只有一行,1个整数,表示接水所需的总时间。
25 样例输入:
26 样例输入#1:
27 5 3
28 4 4 1 2 1
29 样例输出#1:
30 4
31 样例输入#2
32 8 4
33 23 71 87 32 70 93 80 76
34 样例输出#2
35 163
36 */
37 int main(){
38 /**
39 解题思路:排队是固定的,但是水龙头的个数条件是变化的,
40 所以是把每次增加一个后的水龙头进行一次排序。
41 */
42 int n,m,b;
43 cin >> n >> m;
44 int a[10001];
45 memset(a,0,sizeof(a));//将数组a的值全部初始化为0
46 for(int i = 0;i <n;i++){
47 cin >> b;
48 a[0] = a[0] + b;
49 sort(a,a + m);//排序时只将已经登记过的同学进行排序
50 }
51 cout << a[m - 1] << endl; //当最后一个水龙头关闭以后
52 return 0;
53 }
1 #include <iostream>
2 #include <cstdio>
3 #include <string>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7 /**
8 题目描述:
9 有n个同学在一个水龙头前排队接水,假如每个人接水的时间
10 为Ti,请编程找出这n个人排队的顺序,使得n个人的平均等待
11 时间最小。
12 输入格式:
13 输入共两行:
14 第一行为n个人;
15 第二行分别表示第1个人到第n个人每人接水花的时间T1,T2..Tn
16 输出共两行:
17 第一行为一种排队的顺序,即1到n的一种排列。
18 第二行为这种排列方案下的平均等待时间(保留小数点后2位)
19 样例输入#1:
20 10
21 56 12 1 99 100 234 33 55 99 812 错
22 56 12 1 99 1000 234 33 55 99 812 对
23 样例输出#1:
24 3 2 7 8 1 4 9 6 10 5
25 291.90
26
27 解析:
28 “最优化” 方案。
29 */
30 struct person{
31 int t;
32 int idx;
33 }a[1000001];
34 //排序规则
35 bool comp(person a,person b){
36 return a.t < b.t;
37 }
38 int main(){
39 double avgt;
40 double s = 0,t = 0;
41 int n;
42 cin >> n;
43 //将n个同学的等待时间放入到a结构体的t时间中,同时进行编号
44 for(int i = 1;i <= n;i++){
45 cin >> a[i].t;
46 a[i].idx = i;
47 }
48 //排序
49 sort(a + 1,a + (n + 1),comp);
50 //统计
51 for(int i = 1;i <= n;i++){
52 cout << a[i].idx << " ";
53 t = t + a[i - 1].t;//求当前这个同学花费的总时间
54 s = s + t; //求所有同学花费的总时间
55 }
56 avgt = s / n;
57 cout << endl;
58 printf("%0.2lf",avgt);
59 return 0;
60 }
1 #include <iostream>
2 #include <cstdio>
3 #include <string>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7 /**
8 题目描述:
9 有n个同学在一个水龙头前排队接水,假如每个人接水的时间
10 为Ti,请编程找出这n个人排队的顺序,使得n个人的平均等待
11 时间最小。
12 输入格式:
13 输入共两行:
14 第一行为n个人;
15 第二行分别表示第1个人到第n个人每人接水花的时间T1,T2..Tn
16 输出共两行:
17 第一行为一种排队的顺序,即1到n的一种排列。
18 第二行为这种排列方案下的平均等待时间(保留小数点后2位)
19 样例输入#1:
20 10
21 56 12 1 99 1000 234 33 55 99 812
22 样例输出#1:
23 3 2 7 8 1 4 9 6 10 5
24 291.90
25
26 解析:
27 “最优化” 方案。
28 */
29 struct person{
30 int t;
31 int idx;
32 }a[1000001];
33 //排序规则
34 bool comp(person a,person b){
35 return a.t < b.t;
36 }
37 int main(){
38 double avgt;
39 double s = 0,t = 0;
40 int n;
41 cin >> n;
42 //将n个同学的等待时间放入到a结构体的t时间中,同时进行编号
43 for(int i = 1;i <= n;i++){
44 cin >> a[i].t;
45 a[i].idx = i;
46 }
47 //排序
48 sort(a + 1,a + (n + 1),comp);
49 //统计
50 for(int i = 1;i <= n;i++){
51 cout << a[i].idx << " ";
52 t = t + a[i - 1].t;//求当前这个同学花费的总时间
53 s = s + t; //求所有同学花费的总时间
54 }
55 avgt = s / n;
56 cout << endl;
57 printf("%0.2lf",avgt);
58 return 0;
59 }
1 /**
2 【例1】排队打水问题
3 有N个人排队到R个水龙头去打水,他们装满水桶的时间为T1,T2,…,Tn为整数且各不相等,
4 应如何安排他们的打水顺序才能使他们花费的时间最少?
5 【算法分析】
6 由于排队时,越靠前面的计算的次数越多,显然越小的排在越前面得出的结果越小
7 (可以用数学方法简单证明,这里就不再赘述),所以这道题可以用贪心法解答,基本步骤:
8 (1)将输入的时间按从小到大排序;
9 (2)将排序后的时间按顺序依次放入每个水龙头的队列中;
10 (3)统计,输出答案。
11 【样例输入】
12 4 2 4人打水,2个水龙头
13 2 6 4 5 每个人打水时间
14 参考程序主要框架如下:
15 */
16 #include <iostream>
17 #include <cstdio>
18 #include <string>
19 #include <cstring>
20 #include <algorithm>
21 using namespace std;
22 //a数组存储每位同学接水所用的时间。
23 //s数组存储大家等待的时间
24 int s[10001],a[10001];
25 int main(){
26 int n,r;
27 cin >> n >> r;
28 for(int i = 1;i <= n;i++){
29 cin >> a[i];
30 }
31 sort(a + 1,a + (n + 1));
32 int j = 0,minx = 0;
33 //贪心算法求解
34 for(int i = 1;i <= n;i++){
35 j++;
36 if(j == (r + 1)){//前r个人为一组,第r+1个人回到第一个水龙头
37 j = 1;
38 }
39 s[j] += a[i];//加上等待的时间
40 minx += s[j];
41 }
42 cout << minx << endl;
43 return 0;
44 }
1 /**
2 题目描述
3
4 有n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这n个人排队的一种顺序,使得n个人的平均等待时间最小。
5
6 输入输出格式
7
8 输入格式:?
9 输入文件共两行,第一行为n;第二行分别表示第1个人到第n个人每人的接水时间T1,T2,…,Tn,每个数据之间有1个空格。
10
11 输出格式:?
12 输出文件有两行,第一行为一种排队顺序,即1到n的一种排列;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。
13
14 输入输出样例
15
16 输入样例#1:?
17 10?
18 56 12 1 99 1000 234 33 55 99 812?
19 输出样例#1:?
20 3 2 7 8 1 4 9 6 10 5?
21 291.90?
22 说明
23
24 n<=1000
25
26 ti<=1e6,不保证ti不重复
27 ?
28
29 【思路】
30
31 例1:甲乙丙丁戊5个人去水房打水,分别需要2、4、7、10、13分钟,若只有一个水龙头,想5人打水和等待的时间之和最短,则最短时间为多少?
32
33 分析:5个人打水的总时间是不变的为2+4+7+10+13=36分钟,而等待时间受打水者的时间限制,只有打水者时间短,才能使等待时间短。所以让打水者速度从快到慢排队打水,则按照甲乙丙丁戊的顺序打水。甲先打2分钟,其他四人一共等待了2×4=8分钟,乙打水4分钟,剩下三人打水共等待了4×3=12分钟,丙打水7分钟,剩下两人打水共等待了7×2=14分钟,丁打水10分钟,最后一人等待10分钟,所以合计等待时间8+12+14+10=44分钟。则所求最短时间为36+44=80分钟。
34
35 等待时间等于i:1~n? ?sum += (n-i)*a[i]
36 */
37 #include<iostream>
38 #include<iomanip>
39 #include<algorithm>
40 #define MAXN 1005
41 using namespace std;
42 struct paidui{
43 int value;
44 int p;
45 };
46 paidui a[MAXN];
47 bool cmp(const paidui &a, const paidui &b)
48 {
49 if(a.value == b.value)//时间相同,先来的先排序
50 return a.p < b.p;
51 else
52 return a.value < b.value;//否则按照花费时间从小到大排序
53 }
54 int main()
55 {
56 int n;
57 cin >> n;
58 for(int i = 1; i <=n; ++i)
59 {
60 cin >> a[i].value;
61 a[i].p = i;
62 }
63 sort(a+1,a+1+n,cmp);
64 double sum=0;//必须用double
65 for(int i = 1; i <= n; ++i)
66 {
67 cout << a[i].p << " ";
68 sum += (n-i)*a[i].value;
69 //cout << "sum = " << sum << endl;
70 }
71 cout << endl;
72 cout << fixed << setprecision(2) << sum/n << endl;
73 return 0;
74 }
1 #include <iostream>
2 #include <cstdio>
3 #include <string>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7 /**
8 题目描述:
9 有n个同学在一个水龙头前排队接水,假如每个人接水的时间
10 为Ti,请编程找出这n个人排队的顺序,使得n个人的平均等待
11 时间最小。
12 输入格式:
13 输入共两行:
14 第一行为n个人;
15 第二行分别表示第1个人到第n个人每人接水花的时间T1,T2..Tn
16 输出共两行:
17 第一行为一种排队的顺序,即1到n的一种排列。
18 第二行为这种排列方案下的平均等待时间(保留小数点后2位)
19 样例输入#1:
20 10
21 56 12 1 99 1000 234 33 55 99 812 对
22 样例输出#1:
23 3 2 7 8 1 4 9 6 10 5
24 291.90
25 举例佐证:
26 假设有五位同学去打水,甲乙丙丁戊,接水分别所需的时间为:2 4 7 10 13.
27 甲 乙 丙 丁 戊
28 2 4 7 10 13
29 分析:
30 ①打水的总时间:2 + 4 + 7 + 10 + 13 = 36
31 ②尽量让耗时短的同学排前面
32 甲 乙 丙 丁 戊
33 ③甲打水所需时间:2
34 乙打水所需时间:6
35 丙打水所需时间:13
36 丁打水所需的时间:23
37 戊打水所需的时间:36
38 所有人打水所需时间:80
39 */
40
41 //结构体,用来表示每位同学的打水时间Ti,表示为t,每位同学的编号idx.
42 struct person{
43 int t;
44 int idx;
45 }a[10000001];
46 //排序规则
47 bool comp(person a,person b){
48 if(a.t == b.t){
49 return a.idx < b.idx;
50 }else{
51 return a.t < b.t;
52 }
53 }
54 int main(){
55 int n;//n个同学去打水
56 cin >> n;
57 //循环将每位同学打水所需的时间存入到结构体中
58 for(int i = 1;i <= n;i++){
59 //将每位同学打水总时间存入到结构体a中,
60 //并且赋值给t这个时间变量。
61 cin >> a[i].t;
62 //将编号存入到结构体a中,并且赋值给idx这个变量
63 a[i].idx = i;
64 }
65 //结构体排序必须指定排序规则:升序、降序
66 sort(a + 1,a + (n + 1),comp);
67 // for(int i = 1;i <= n;i++){
68 // cout << a[i].idx << " ";
69 // }
70 // cout << endl;
71 // for(int i = 1;i <= n;i++){
72 // cout << a[i].t << " ";
73 // }
74
75 //cout << a[8].t << " " << a[8].idx << endl;
76 double sum = 0;//总和时间必须用double
77 //贪心算法求最优解
78 for(int i = 1;i <= n;i++){
79 cout << a[i].idx << " ";
80 sum += (n - i)*a[i].t;
81 //cout << sum << endl;
82 //因为第一个同学不需要排队
83 /**
84 举例佐证
85 编号: 1 2 3 4 5 6 7 8 9 10
86 原始数据: 56 12 1 99 1000 234 33 55 99 812
87
88 错误:编号: 10 9 8 7 6 5 4 3 2 1
89 已排好: 812 99 55 33 234 1000 99 1 12 56
90
91 正确: 编号:3 2 7 8 1 4 9 6 10 5
92 打水量从小到大排列好:1 12 33 55 56 99 99 234 812 1000
93 sum += (n - i)*a[i].t;
94 假设第i个同学在打水,Ti = Ti + T(i-1) + T(i -2 ) + T1
95 i = 3
96 n - i = 7
97
98 i = 5
99 n - i = 5
100
101 i = 8
102 n - i = 2
103 */
104
105 }
106 cout << endl;
107 printf("%.2lf",sum/n);
108 return 0;
109 }
1 //do .. while
2 #include <iostream>
3 using namespace std;
4 int main(){
5 // 1992个1992的末两位数是多少?
6 /**
7 sum总和,考虑溢出的问题
8 ①积的个位与十位只与被乘数和乘数的个位与十位有关。
9 ②本次的乘积是下一次相乘的被乘数 ,因此只需要取末两位参与运算即可。
10 1992 * 1992
11 92^1992
12 */
13 int a = 1, t = 0;
14 do{
15 ++t;
16 a = (a * 92) % 100;
17 }while(t != 1992);
18 cout << a << endl;
19 return 0;
20 }
1 #include <iostream>
2 using namespace std;
3 //操场排队
4 int main(){
5 int x = 0;
6 bool yes = true;
7 do{
8 x += 7;
9 if(x % 2 == 1 && x % 3 == 1 &&
10 x % 4 == 1 && x % 5 == 1 &&
11 x % 6 == 1){
12 yes = false;
13 }
14 }while(yes);
15 cout << x << endl;
16 return 0;
17 }
1 #include <iostream>
2 using namespace std;
3 //使用do...while求解弹跳球的高度
4 int main(){
5 int c = 1;
6 double h,sum = 0;
7 cin >> h;
8 sum = h;
9 do{
10 h = h * 0.5;
11 sum += 2*h;
12 c++;
13 }while(c <= 9);
14 cout << sum << endl;
15 cout << h << endl;
16 return 0;
17 }
1 #include <iostream>
2 using namespace std;
3 //使用do...while求解弹跳球的高度
4 int main(){
5 double h,sum = 0;
6 int c = 0;
7 cin >> h;
8 sum = h;
9 while(c <= 10){
10 ++c;
11 h = h * 0.5;
12 sum += 2 * h;
13 }
14 cout << sum << endl;
15
16 }
1 #include <iostream>
2 using namespace std;
3 //n! = n * (n - 1) * (n - 2) *.....*1
4 int main(){
5 int n,sum = 1;
6 cin >> n;
7 for(int i = n;i >= 1;i--){
8 sum *= i;
9 }
10 cout << sum << endl;
11 return 0;
12 }
1 #include <iostream>
2 using namespace std;
3 //s = 1! + 2! + .....+ 10!
4 int main(){
5 int sum2 = 1;
6 int sum1 = 1;
7 for(int i = 1;i <= 10;i++){
8 for(int j = 1;j <= i;j++){
9 sum1 *= j;
10 }
11 sum2 += sum1;
12 }
13 cout << sum1+sum2 << endl;
14 return 0;
15 }
复习要求:自学73页,4.19 阶乘之和。
作业要求:【上机练习】
1.求阶乘的和。
2.求出e的值。
3.计算多项式的值。
提交方式:
建议OJ提交,没有OJ账号的同学单独发送.cpp源文件。
提交时间:
2019年7月19日(周五)晚23:00之前。



代码虐我千百遍,我待代码如初恋!--gogo-BUG!
吃过符号的亏,上过大小写的当!--gogo-DEBUG!

浙公网安备 33010602011771号