《挑战程序设计竞赛》-第一章

目录

 

第一章:蓄势待发,准备篇:

内容梳理:

1 : 给出三条边,问能否构成三角形:

2:Ants poj1852

3:抽签问题

1:O(n^4)

2:O(n^3logn)

3:O(n^2longn)

 


 

第一章:蓄势待发,准备篇:

内容梳理:

1 : 给出三条边,问能否构成三角形:

首先算出三边的和,然后算出最大边的值,用三边和减去最大边的值就是其他两个边的长度,最用利用两边之和大于第三边来判断是否能够成三角形。

2:Ants poj1852

在一根长为L厘米的水平木棍上有n只蚂蚁,它们以每秒1cm/s的速度走到木棍一端就会掉下去。现在知道它们起始位置(相对于木棍左端点的距离)。但是不知道它们爬行的方向。两只蚂蚁相遇后,它们会掉头往反方向走。求所有蚂蚁都落下木棍的最短时间和最长时间。

注意是所有蚂蚁爬出的最大最小时间,不知道方向,如果用递归的话肯定会超时的,利用贪心的思想,只要求出每只蚂蚁爬出的最小时间,然后再比较找出最小时间的最大值就是所有蚂蚁爬出的最小时间。同理,最大时间就是求出每只蚂蚁爬出的最大时间,比较找出最大时间的最大值。

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=1e6+10;
int a[maxn];
int n;
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    while(n--)
    {
        int l,m;
        cin>>l>>m;
        int min_number=0;
        int max_number=0;
        for(int i=0;i<m;++i)
        {
            scanf("%d",&a[i]);
            min_number=max(min_number,min(a[i],l-a[i]));
            max_number=max(max_number,max(a[i],l-a[i]));
        }
        printf("%d %d\n",min_number,max_number);
    }
    return 0;
}

3:抽签问题

1:O(n^4)

四层for循环:

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=1e6+10;
int a[maxn];
int n,m;
bool solve()
{
    bool f=false;
    for(int e=0; e<n; ++e)
        for(int b=0; b<n; ++b)
            for(int c=0; c<n; ++c)
                for(int d=0; d<n; ++d)
                    if(a[e]+a[b]+a[c]+a[d]==m)
                        f=true;
    return f;
}
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>m)
    {
        for(int i=0; i<n; ++i)
            cin>>a[i];
        if(solve())
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

显然,在搜索第三层后,我们已经确定了使得条件成立的第四个数字是多少(m-a[e]-a[b]-a[c]),我们只需要判断这组数据里面是否有这个数就行了,这个时候我们用到了时间复杂度为O(logn)的算法-二分搜索。

2:O(n^3logn)

进行这个操作之前我们需要给原本的数据排个序,使得整个数据是按照从小到大的顺序排列的,然后直接调用STL里面的binary_searth()函数即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
int a[maxn];
int n,m;
bool solve()
{
    bool f=false;
    for(int e=0; e<n; ++e)
        for(int b=0; b<n; ++b)
            for(int c=0; c<n; ++c)
                    if(binary_search(a,a+n,m-a[e]-a[b]-a[c]))
                        f=true;
    return f;
}
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>m)
    {
        for(int i=0; i<n; ++i)
            cin>>a[i];
        sort(a,a+n);
        if(solve())
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

刚才我们是着眼于四层循环程序中最内层的循环。接下来,让我们着眼于内侧的两个循环,同刚才一样的思路,内侧的两个循环是在:检查是否有c和d使得kc+kd=m-ka-kb这种情况下并不能直接使用二分搜索,但是,如果预先枚举出kc+kd所得到n^2个数字并排好序,便可以利用二分搜索了。

3:O(n^2longn)

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
int a[maxn];
int aa[maxn];
int n,m;
bool solve()
{
    bool f=false;
    for(int e=0; e<n; ++e)
        for(int b=0; b<n; ++b)
                if(binary_search(aa,aa+n*n,m-a[e]-a[b]))
                    f=true;
    return f;
}
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>m)
    {
        for(int i=0; i<n; ++i)
            cin>>a[i];
        for(int i=0; i<n; ++i)
            for(int j=0; j<n; ++j)
            {
                aa[i*n+j]=a[i]+a[j];
            }
        sort(aa,aa+n);
        if(solve())
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值