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之前。

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   

 

posted @ 2019-07-17 17:31  灰灰老师  阅读(782)  评论(0)    收藏  举报