• [贪心]


    一、区间调度问题

    有n项工作,每项工作分别在a[i].begin开始,在a[i].end结束,求最多可参加的任务数。

    有三种可选方案:

    1.每次都选取结束时间最早的工作。

    2.每次都选取用时最短的工作。

    3.每次都选取与最少可选工作有重叠的工作。

    实验证明:第一个是正确的,其他两种都可找到反例。

    证明:

    显然,该算法最后选出的区间不互相重叠,下面证明所选出区间的数量是最多的。设fi为该算法所接受的第i个区间的右端点坐标,gi为某最优解中的第i个区间的右端点坐标。

    命题1.1  当i>=1时,该算法所接受的第i个区间的右端点坐标fi<=某最优解中的第i个区间的右端点坐标gi。

    该命题可以运用数学归纳法来证明。对于i=1,命题显然为真,因为算法第一个选择的区间拥有最小右端点坐标。令i>1,假定论断对i-1为真,即fi-1<=gi-1。则最优解的第i个可选区间所组成的集合包含于执行该算法时第i个可选区间所组成的集合;而当算法选择第i个区间时,选的是在可选区间中右端点坐标最小的一个,所以有fi<=gi。证毕。

    设该算法选出了k个区间,而最优解选出了m个区间。

    命题1.2  最优解选出的区间数量m=该算法选出的区间数量k。

    假设m>k,根据命题1.1,有fk<=gk。由于m>k,必然存在某区间,在gk之后开始,故也在fk之后开始。而该算法一定不会在选了第k个区间后停止,还会选择更多的区间,产生矛盾。所以m<=k,又因为m是最优解选出区间个数,所以m=k。

    综上所述,算法选出的区间是最优解。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 int main()
     8 {
     9     int n;
    10     char s[2010];
    11     cin >> n;
    12     for (int i = 1; i <= n; i++)
    13         cin >> s[i];
    14     int a = 1, b = n;
    15     int ans = 0;
    16     while (a <= b) {
    17         bool flag = 0;
    18         for (int i = 0; a + i <= b; i++)
    19         {
    20             if (s[a + i] < s[b - i])
    21             {
    22                 flag = 1;
    23                 break;
    24             }
    25             else if (s[a + i] > s[b - i])
    26             {
    27                 flag = 0;
    28                 break;
    29             }
    30         }
    31         if (flag == 1) {
    32             ans++;
    33             cout << s[a++];
    34             if (ans % 80 == 0)    cout << endl;
    35         }
    36         else {
    37             ans++;
    38             cout << s[b--];
    39             if (ans % 80 == 0)    cout << endl;
    40         }
    41     }
    42     cout << endl;
    43     return 0;
    44 }
    区间调度

     二、字典序最小问题

    给定长度为N的字符串S,要构造一个长度为N的字符串T。有两种操作:

    1.从S的头部删除一个字符,加到T的尾部

    2.从S的尾部删除一个字符,加到T的尾部

    目标是要构造字典序尽可能小的字符串T

    方法:

    反转字符串S的字符串S1

    按照字典序比较S和S1

    若S较小 就从头部删除

    若S1较小 就从尾部删除

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 int main()
     8 {
     9     int n;
    10     char s[2010];
    11     cin >> n;
    12     for (int i = 1; i <= n; i++)
    13         cin >> s[i];
    14     int a = 1, b = n;
    15     int ans = 0;
    16     while (a <= b) {
    17         bool flag = 0;
    18         for (int i = 0; a + i <= b; i++)
    19         {
    20             if (s[a + i] < s[b - i])
    21             {
    22                 flag = 1;
    23                 break;
    24             }
    25             else if (s[a + i] > s[b - i])
    26             {
    27                 flag = 0;
    28                 break;
    29             }
    30         }
    31         if (flag == 1) {
    32             ans++;
    33             cout << s[a++];
    34             if (ans % 80 == 0)    cout << endl;
    35         }
    36         else {
    37             ans++;
    38             cout << s[b--];
    39             if (ans % 80 == 0)    cout << endl;
    40         }
    41     }
    42     cout << endl;
    43     return 0;
    44 }
    字典序最小

    三、添加守卫

    直线上有N个点。从这N个点中选择若干个,给他们加上标记。对每一个点,距离为R以内的区域内必须有带有标记的点。

    在满足这个条件的同时,尽可能少的点添加标记。请问至少要有多少点被加上标记。

    方法:

    从第一个点开始,找到距离R范围内最右边的点加上标记

    再从标记的点开始,找R的范围外的第一个点 作为起始点。

    从起始点开始重复。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 int main()
     8 {
     9     int a, b;
    10     while (cin >> a >> b) {
    11         if (a ==-1 && b==-1)    break;
    12         int s[1010],ans=0;
    13         for (int i = 1; i <= b; i++)
    14             cin >> s[i];
    15         sort(s + 1, s + b + 1);
    16         int i = 1;
    17         while (i <= b) {
    18             int c = s[i++];
    19             while (i <= b && s[i] <= a + c)    i++;
    20             int p = s[i - 1];
    21             ans++;
    22             while (i <= b && s[i] <= p + a)    i++;
    23         }
    24         cout << ans << endl;
    25     }
    26     return 0;
    27 }
    View Code

    四、木板切割

    把一块长木板切割成N块,每次切割木板时,需要的开销为这块木板的长度。

    求出将木板切割完最小的开销。

    输入 :

    3

    8  5  8

    输出:

    34(8+5+13+8)//另一种是(8+8+16+5)不是最小舍去。

    方法:

    由于每次切木板都是切成两部分,可以参照二叉树。

    木板长度*节点的深度。

    对于最优解来说:最短的板和次短的板应是兄弟节点,最短的板也应该是深度最大的叶子节点。

    在数组中找最小的和次小的,答案加上这两个数,再把这两个数合并起来的一个大数插入数组中(这两个数已经无用),总数-1.

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 int main()
     8 {
     9     int n;
    10     long long ans = 0;//long long 
    11     int a[20010];
    12     cin >> n;
    13     for (int i = 1; i <= n; i++)
    14         cin >> a[i];
    15     while (n > 1) {
    16         int min1 = 1, min2 = 2;
    17         if (a[min1] > a[min2])    swap(min1, min2);
    18         for (int i = 3; i <= n; i++)
    19         {
    20             if (a[i] < a[min1]) {
    21                 min2 = min1;
    22                 min1 = i;
    23             }
    24             else if (a[i] < a[min2]) {
    25                 min2 = i;
    26             }
    27         }
    28         int t = a[min1] + a[min2];
    29         ans += t;
    30         if (min1 == n)    swap(min1, min2);//若a[n-1]是最小的数,就可以不要。
    31         a[min1] = t;
    32         a[min2] = a[n];
    33         n--;
    34     }
    35     cout << ans << endl;
    36     return 0;
    37 }
    View Code
    No matter how you feel, get up , dress up , show up ,and never give up.
  • 相关阅读:
    Python 3 Mysql 增删改查
    Python3 MySQL 数据库连接 -PyMySQL
    java 获取cookie
    Python 通过配置文件 读取参数,执行测试用例,生成测试报告并发送邮件
    Python 操作 Excel 、txt等文件
    SonarQube代码质量管理平台安装与使用
    Python + HTMLTestRunner + smtplib 完成测试报告生成及发送测试报告邮件
    Python 解析Xml文件
    GO语言基础
    FileBeat
  • 原文地址:https://www.cnblogs.com/Kaike/p/9875831.html
Copyright © 2020-2023  润新知