算法入门刷题笔记 Day1

写在前面

好久没更新公众号和博客了,因为最近在研究新的方向,所以很少发文。
笔者接触编程只有一年,这一年间主要研究启发式算法在运筹学中的应用。但是由于编程基础薄弱,在进一步研究复杂运筹学问题时发现基础算法不过关导致写出的代码运行速度很慢,因此很苦恼。所以决定这个暑假补习一下基础算法,主要是刷一些简单的ACM入门题。偶尔会发一些刷题笔记(偶尔!)。和作者有类似目标的同学可以一起交流共勉!

目前在看的教程:
北京理工大学ACM冬季培训课程

算法竞赛入门经典/刘汝佳编著.-2版可以在这里下载->github

课程刷题点
Virtual Judge

刷题代码都会放在github上,欢迎一起学习进步!

放假了就是轻松,今天先吧Day1的剩下5题解决了,可以搞运筹去咯~

Day1 - H - Lala Land and Apple Trees

在这里插入图片描述
一条数轴(LaLa land),轴上分布多个点(apple tree),Amr可以在点与点之间反复横跳:往一个方向走,碰到树就摘苹果,再调头…问Amr最多摘多少苹果。

思路比较简单:把原点左边的点(x为负)按x从大到小排序、右边的点从小到大排序,取较小的size,累加size范围内的apple数。记得判断边界。

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

// #define LOCAL

bool cmp1(pair<int, int> a, pair<int, int> b)
{
    return a.first < b.first;
}

bool cmp2(pair<int, int> a, pair<int, int> b)
{
    return a.first > b.first;
}

int main()
{
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
#endif
    int n;
    scanf("%d", &n);
    vector<pair<int, int>> left;
    vector<pair<int, int>> right;

    for (int i = 0; i < n; i++)
    {
        int pos;
        int appleNr;
        scanf("%d %d", &pos, &appleNr);
        if (pos > 0)
            right.push_back(make_pair(pos, appleNr));
        else
            left.push_back(make_pair(pos, appleNr));
    }

    sort(left.begin(), left.end(), cmp2);
    sort(right.begin(), right.end(), cmp1);

    int sum = 0;
    int size;
    if (left.size() < right.size())
    {
        size = left.size();
        sum += right[size].second;
    }
    else if (left.size() > right.size())
    {
        size = right.size();
        sum += left[size].second;
    }
    else
        size = left.size();

    for (int i = 0; i < size; i++)
        sum += left[i].second + right[i].second;
    printf("%d", sum);
    return 0;
}

Day1 - I - Watering Flowers

在这里插入图片描述
二维坐标系上一堆点(flower),有两个圆心(fountain),问如何确定较小的半径的平方和(r12+r22r_1^2 + r_2^2),使得所有点被包围在两个圆内。

我的思路是递推方法,每多一个点判断是否在圆的范围内,不是则选择Δr2Delta r^2较小的r2r^2做替换。

结果只得到一个WA呜呜呜…

网上有人说排序什么的,感觉不如我的快。我也看到有AC的答案是和我一样的,思路应该没问题,又那里搞错了可能…

判断两个r的时候可以先判断一个再计算下一个,可以节省时间。

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

// #define LOCAL
// Wrong answer on test 5 速度明明很快的说

int main()
{
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
#endif
    long long n, x1, y1, x2, y2;
    cin >> n >> x1 >> y1 >> x2 >> y2;
    long long r1_pow = 0, r2_pow = 0;

    for (int i = 0; i < n; i++)
    {
        long long x, y;
        cin >> x >> y;
        long long dis_pow1 = pow(x - x1, 2) + pow(y - y1, 2);
        if (dis_pow1 > r1_pow)
        {
            long long dis_pow2 = pow(x - x2, 2) + pow(y - y2, 2);
            if (dis_pow2 > r2_pow)
                if ((dis_pow1 - r1_pow) > (dis_pow2 - r2_pow))
                {
                    r2_pow = dis_pow2;
                }
                else
                {
                    r1_pow = dis_pow1;
                }
        }
    }

    cout << (r1_pow + r2_pow) << endl;
    return 0;
}

Day1 - J - Hints of sd0061

在这里插入图片描述
字符串处理。这题有点绕,我看了好久都没大看懂,就直接找了答案。答案看来看去也没什么意思,而且贴上去居然是TL…就暂时不管了。

Day1 - K - Anton and Lines

在这里插入图片描述
判断一次函数图像是否有焦点。简单数学题,就是判断边界是否交叉嘛。注意根据Example,边界上重合不算焦点。

我的思路是根据两个边界上的y值sort,然后判断sort后是否一样。如果遇到不一样的,再判断两边上的y值有相同。有相同的y值,那就不可能相交了。

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;

// #define LOCAL
typedef long long ll;

ll x1, x2;

struct Line
{
    int id;
    ll k;
    ll b;
    ll y1;
    ll y2;
    Line(int id, ll k, ll b)
    {
        this->id = id;
        this->k = k;
        this->b = b;
        this->y1 = k * x1 + b;
        this->y2 = k * x2 + b;
    }
};

bool cmp1(Line l1, Line l2)
{
    return l1.y1 > l2.y1;
}

bool cmp2(Line l1, Line l2)
{
    return l1.y2 > l2.y2;
}

int main()
{
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
#endif
    ll n;
    cin >> n;
    cin >> x1 >> x2;
    vector<Line> line;
    for (int i = 0; i < n; i++)
    {
        ll k, b;
        cin >> k >> b;
        line.push_back(Line(i, k, b));
    }

    vector<Line> temp_line(line);
    sort(line.begin(), line.end(), cmp1);
    sort(temp_line.begin(), temp_line.end(), cmp2);

    int flag = 0;
    for (int i = 0; i < n; i++)
    {
        if ((line[i].id != temp_line[i].id) && (line[i].y1 != temp_line[i].y1) && (line[i].y2 != temp_line[i].y2))
        {
            flag = 1;
            break;
        }
    }

    if (flag)
        cout << "YES" << endl;
    else
        cout << "NO" << endl;

    return 0;
}

Day1 - L - New Year and Counting Cards

在这里插入图片描述
最后一题了,终于…又是字符串。有一堆卡片,卡片代表小写字母和数字的对应关系。

一条规则:元音字符可以转换为偶数。

给一堆卡片的一个面,若要判断是否符合这个规则,问最坏的情况下最少需要翻开几张卡片的另一面?

好傻…就是找字符串里有多少元音字母+奇数。

学会了一个find函数哈,不亏不亏~
string.find(string)可以返回内部子字符串在外部string中的位置,若是不存在则返回string::npos。

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;

// #define LOCAL

int main()
{
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
#endif
    string str;
    cin >> str;

    string vowel = "aeiou";
    string odd = "13579";

    int sum = 0;
    for (int i = 0; i < str.length(); i++)
    {
        if (vowel.find(str[i]) != string::npos)
            sum++;
        else if (odd.find(str[i]) != string::npos)
            sum++;
    }

    cout << sum << endl;

    return 0;
}

Day1刷题总结

那么Day1的题就刷完了。还是有点好玩的,但WA的时候也挺折磨人的…那么下一步先看一天课本,课本好久没看了,可能会做下课本里的习题吧,然后再看视频,刷Day2。(话说这个Day真的是一天的刷题量吗…)

原文地址:https://www.cnblogs.com/zll-hust/p/13288817.html