1.6 轻松热身

1.6.1 三角形

n根棍子,i号棍子的长度为ai。从中选出3根棍子组成周长尽可能长的三角形。输出最大的周长,如果不能组成三角形,输出0。
限制条件:3 <= n <= 100;1 <= ai <= 10^6

O(n^3)

#include <iostream>

using namespace std;
int numberset[100];
int main()
{
    int num, ans = 0;
    cin >> num;

    for(int i = 0; i < num;i++)
    {
        cin >> numberset[i];
    }

    for(int i = 0;i < num;i++)
    {
        //使得i < j < k 避免重复
        for(int j = i + 1;j < num;j++)
        {
            for(int k = j + 1;k < num;k++)
            {
                int len = numberset[i] + numberset[j] + numberset[k];
                int maxsidelength = max(numberset[i], max(numberset[j], numberset[k]));
                int rest = len - maxsidelength;

                /**只要两边之和大于第三边就可以构成三角形
                ***为什么不用考虑差的情况**/
                if(maxsidelength < rest)//两边之和大于第三边
                {
                    ans = max(len, ans);
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

白书上说还有一种O(nlogn)的做法,查了一下
与上面的重要区别就是读入边长后先进行排序,因为我们要做的判断是两边之和>第三边(max),那么排序后如果总的Max值比其后两边长的和还要大,就不必再依次判断,含有这个总max的组合一定是无法组成三角形的。这是就再重复上面的过程,对次大,次次大……进行判断。同样的,如果max比其后两边的和要小,一次判断说明可以组成三角形。
(因为我们的题目求的是周长尽可能大,也就是边长的选用要尽可能大)

#include <iostream>
#include <algorithm>
using namespace std;
int numberset[100];
int main()
{
    int num, ans = 0;
    cin >> num;

    for(int i = 0; i < num;i++)
    {
        cin >> numberset[i];
    }

    sort(numberset, numberset + num);
    for(int i = num - 1;i >= 2;i--)
    {
        if(numberset[i] < numberset[i-1] + numberset[i-2])
        {
            ans = numberset[i] + numberset[i-1] +numberset[i-2];
            break;
        }
    }

    cout << ans << endl;
    return 0;
}

1.6.2 Ants

n只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行。当蚂蚁爬到竿子的端点时就会掉落。由于竿子太细,两只蚂蚁相遇时,它们不能交错通过,只能各自反向爬回去。对于每只蚂蚁,我们知道它距离竿子左端的距离xi,但不知道它当前的朝向。请计算所有蚂蚁落下竿子所需的最短时间和最长时间。
1 <= L <= 10^6
1 <= n <= 10^6
0 <= xi <= L

O(2^n)穷竭搜索
枚举所有蚂蚁的初始朝向组合

O(n)
最短时间:所有蚂蚁都朝着最近的端点走
最长时间:视为穿过彼此身体 → 求蚂蚁到端点的最大距离
限制条件n <= 10

#include <iostream>
#include <algorithm>
using namespace std;
int L, //杆子长度
    n; //蚂蚁只数
int a[100000];
int main()
{
    cin >> L >> n;
    for(int i = 0;i < n; i++)
    {
        cin >> a[i];
    }
    sort(a, a + n);

    cout << "min = " << a[0];
    cout << "max = " << a[n-1];
    return 0;
}

这里有一个问题,题目输入给出的距离是针对左端点的。而我们的蚂蚁是可以双向移动的,所以如果用sort只是找到了距离左端点最近和最远的两只蚂蚁,但是如果他们可以往右走,结果完全可以不同。

#include <iostream>
#include <algorithm>
using namespace std;
int L, //杆子长度
    n, //蚂蚁只数
    maxans,
    minans;
int a[100000];
int main()
{
    cin >> L >> n;
    for(int i = 0;i < n; i++)
    {
        cin >> a[i];
    }

    for(int i = 0;i < n; i++)
    {
        maxans = max(maxans, max(a[i], L - a[i]));

        minans = max(minans, min(a[i], L - a[i]));
        //minans = min(minans, min(a[i], L - a[i]));
        //注意求min的时候外层应该取max,因为必须要最后一支蚂蚁走掉以后才算过程结束
    }

    cout << "min = " << minans;
    cout << "max = " << maxans;
    return 0;
}

1.6.3 难度增加的抽签问题

在这里插入图片描述
在这里插入图片描述

O(n^3logn) 内部[二分搜索]

(http://www.cnblogs.com/wkfvawl/p/9475939.html)

#include <iostream>
#include <algorithm>
using namespace std;
int numberset[1001] = {0};
int number, x, m, check;
int main()
{
    //1 <= n <= 1000
    cin >> number >> m;
    for(int i = 0;i < number; i++)
    {
        cin >> numberset[i];
    }

    sort(numberset, numberset + number);

    for(int i = 0;i < number; i++)
    {
        for(int j = 0;j < number; j++)
        {
            for(int k = 0;k < number; k++)
            {
                x = m - numberset[i] - numberset[j] - numberset[k];
                if(binary_search(numberset, numberset + number, x))
                {
                    check = 1;
                    break;
                }
            }
        }
    }

    if(check == 0)
    {
        cout << "NO" << endl;
    }
    else
    {
        cout << "YES" << endl;
    }
    return 0;
}

binary_search的实现

O(n^2logn)

在这里插入图片描述

#include <iostream>
#include <algorithm>
using namespace std;
int numberset[1001] = {0},
    sumset[1000001] = {0};
int number, x, m, check, index;
int main()
{
    //1 <= n <= 1000
    cin >> number >> m;
    for(int i = 0;i < number; i++)
    {
        cin >> numberset[i];
    }

    for(int i = 0;i < number; i++)
    {
        for(int j = 0;j < number; j++)
        {
            sumset[index++] = numberset[i] + numberset[j]; //用set去重?但后面遍历会变麻烦?
            //cout << sumset[index - 1] << "=" << numberset[i] << "+" << numberset[j] << endl;
            //cout << index << endl;
        }
    }

    sort(sumset, sumset + index);

    for(int i = 0;i < number; i++)
    {
        for(int j = 0;j < number; j++)
        {
            x = m - numberset[i] - numberset[j];
            if(binary_search(sumset, sumset + index, x))
            {
                check = 1;
                break;
            }
        }
    }

    if(check == 0)
    {
        cout << "NO" << endl;
    }
    else
    {
        cout << "YES" << endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值