2022-01-15 每日打卡:难题精刷

2022-01-15 每日打卡:难题精刷

写在前面

“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,所刷题目共三个来源:之前没做出来的 ;Leetcode中等,困难难度题目; 周赛题目;某个专题的经典题目,所有代码已AC。每日1-3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。

同时运行 N 台电脑的最长时间

在这里插入图片描述
今天又打了一场周赛,最后一题超时了😥这道题,考完看题解,后知后觉己前几天做过类似的,就是Aggressive cows那道,总结以下:

最优排布问题一般有这么几个思路:

  • 动态规划。比如今天的第三题解决智力问题,出的很快哈哈哈。一看有边界条件,有转移方程(很可能是针对组合/转移的分类讨论)。
  • 贪心。往往是正解,比如这个题,我每次只使用单位1的电,从前n个最大剩余的电池中选就可以。
  • 枚举。 往往是直接寻找最优安排方案超出时间or算法困难。尝试变换角度为控制变量大小,判断是否满足条件! 比如这个题中将“在现有条件的基础上给定天数,判断是否能够维持这些电脑同时运行。”,太妙啦。

我【超时】的解答:

class Solution:
    def maxRunTime(self, n: int, batteries: List[int]) -> int:
        ans = 0
        while(batteries.count(0)<=len(batteries)-n):
            batteries.sort(reverse = True)
            for i in range(n):
                batteries[i]-=1
            ans+=1
        return ans
        

榜一的贪心思路:
首先计算出的 平均值 是时间的上界,因为 存在电池因为不能同时使用而不能使用全部电量

  • 超过平均值的,那些电池给一个电脑从头用到尾,所以不考虑这个电脑 也不考虑这个电池。
  • 直到最大的都不够平均值,那么答案就是剩下的所有电池混用能够维持的最大时间。

为什么这样是正确的呢?借用一个图,相当于用不同的条来填满矩形,几台电脑满足同一行的颜色不同(同一时间不能使用同一块电池)。
请添加图片描述
可以发现,在填充的时候对于大于平均值的一定能满足无论最后ans取几的情况,且超过ans部分怎样都无法排布(试想一下上图的红色,超过ans的部分还有1,排布在哪一行都会发生冲突)。
而对于小于平均值的,我们可以选择任何一行放(此时有 batteries[i] <= avg = len(rows)),所以一定可以全部安置下!
请添加图片描述
枚举+二分的写法:
主要就是要找到上面的check函数的条件为n*x = sum( min(b, x) for b in batteries ),原因在于

  • rows不断变小的过程,原先可选择的行的位置变小,相当于每一行可以选择的条变多了,一定仍然满足;
  • 而rows不断变大的过程,要填满的矩阵也在不断变大,可选择的条数“变少”,可能无法满足条件。

就这样使用二分法不断逼近即可。

class Solution:
    def maxRunTime(self, n: int, batteries: List[int]) -> int:
        tot = sum(batteries)
        l, r = 1, tot // n + 1
        while l < r:
            x = (l + r) // 2
            if n * x <= sum(min(b, x) for b in batteries):
                l = x + 1
            else:
                r = x
        return r - 1

奶酪

在这里插入图片描述
dfs:给自己提个醒,对于这种多输入多输出的问题,每次循环调用一个案例一定记得把变量,数组什么的都还原。

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

const int N = 501, M = 1e4 + 1;
struct Hole
{
    int x, y, z;
    bool flag;
    double operator-(const Hole &other)
    {
        return pow((this->x - other.x), 2) + pow((this->y - other.y), 2) + pow((this->z - other.z), 2);
    }
    friend ostream  &operator<<( ostream &output,const Hole &D )
    { 
        output<<D.x << D.y << D.z;
        return output;            
    }
} holes[M];

int len;
int cnt;
int n, h, r;
stack<Hole> stk;
Hole tmp;
bool ans = false;
stack<Hole> s2;

void func()
{
    
    scanf("%d %d %d", &n, &h, &r);
    cnt = n;
    for (int i = 0; i < cnt; i++)
    {
        scanf("%d %d %d", &holes[i].x, &holes[i].y, &holes[i].z);
        if (holes[i].z <= r)
        {
            stk.push(holes[i]);
            holes[i].flag = false;
        }else{
            holes[i].flag = true;
        }
    }

    while (stk.size())
    {
        tmp = stk.top();
        stk.pop();

        if (tmp.z + r >= h)
        {
            ans = true;
            break;
        }

        for (int i = 0; i < cnt; i++)
        {

            if (holes[i] - tmp <= pow((2 * r),2) && holes[i].flag)
            {
                stk.push(holes[i]);
                holes[i].flag = false;
            }
        }
    }

    if (ans)
    {
        printf("Yes");
    }
    else
    {
        printf("No");
    }
    printf("\n");
}

int main()
{
    scanf("%d", &len);
    for (int i = 0; i < len; i++)
    {
        memset(holes, -1, sizeof holes);
        stk = stack<Hole>();
        ans = false;
        func();
    }
}

拓扑+并查集的做法也是可以的,但是这个oj对python的输入要求很不友好,没有再写。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值