NC20154 [JSOI2007]建筑抢修(贪心)

题目链接

题意:
有 n 个 建 筑 , 每 个 建 筑 有 修 复 时 间 和 截 止 时 间 有n个建筑,每个建筑有修复时间和截止时间 n
只 有 一 个 工 人 , 假 设 路 程 不 需 要 时 间 只有一个工人,假设路程不需要时间
最 多 可 以 让 多 少 个 建 筑 在 截 止 时 间 前 修 复 好 最多可以让多少个建筑在截止时间前修复好
题解:
n < = 15000 n<=15000 n<=15000
感 觉 和 那 个 老 师 教 课 问 题 很 相 似 感觉和那个老师教课问题很相似
想 要 教 尽 量 多 的 课 想要教尽量多的课
只 不 过 那 个 给 的 是 起 止 时 间 , 这 个 是 需 要 时 间 和 截 止 时 间 只不过那个给的是起止时间,这个是需要时间和截止时间

贪 心 可 以 考 虑 几 种 策 略 贪心可以考虑几种策略
1. 按 需 要 时 间 短 的 先 做 1.按需要时间短的先做 1.
2. 按 最 晚 开 始 时 间 ( 即 截 止 时 间 减 需 要 时 间 ) 的 早 晚 来 做 2.按最晚开始时间(即截止时间减需要时间)的早晚来做 2.
3. 按 截 止 时 间 早 的 先 做 3.按截止时间早的先做 3.

首 先 分 析 第 一 种 , 先 做 时 间 短 的 首先分析第一种,先做时间短的
时 间 短 的 但 是 其 实 他 截 止 时 间 很 晚 时间短的但是其实他截止时间很晚
你 做 了 这 件 事 , 反 而 耽 误 了 你 一 件 截 止 时 间 早 的 事 不 能 完 成 你做了这件事,反而耽误了你一件截止时间早的事不能完成
所 以 这 一 种 明 显 不 成 立 所以这一种明显不成立

然 后 分 析 第 二 种 然后分析第二种
如 果 一 件 事 最 晚 开 始 时 间 很 早 , 但 是 他 花 费 时 间 很 长 如果一件事最晚开始时间很早,但是他花费时间很长
在 这 之 间 你 完 全 可 以 做 两 件 比 他 开 始 时 间 晚 的 事 在这之间你完全可以做两件比他开始时间晚的事
所 以 第 二 种 也 不 成 立 所以第二种也不成立

最 后 , 说 一 下 第 三 种 最后,说一下第三种
按 截 止 时 间 早 的 先 做 , 如 果 你 当 前 时 间 如 果 满 足 截 止 时 间 前 做 完 按截止时间早的先做,如果你当前时间如果满足截止时间前做完
那 么 就 做 这 件 事 那么就做这件事
但 是 如 果 这 样 的 话 , 会 出 现 一 个 问 题 但是如果这样的话,会出现一个问题
这 件 事 的 持 续 时 间 很 长 , 导 致 你 本 来 能 做 后 面 两 件 事 的 时 间 被 这 一 件 事 占 用 了 这件事的持续时间很长,导致你本来能做后面两件事的时间被这一件事占用了
所 以 每 次 需 要 有 一 个 反 悔 的 机 会 , 就 是 可 以 重 新 选 择 所以每次需要有一个反悔的机会,就是可以重新选择
那 么 这 个 反 悔 的 机 会 就 用 一 个 堆 维 护 , 让 堆 中 放 每 件 事 的 持 续 时 间 那么这个反悔的机会就用一个堆维护,让堆中放每件事的持续时间
最 大 的 时 间 在 t o p , 如 果 发 现 你 这 件 事 不 能 在 截 止 时 间 前 做 完 最大的时间在top,如果发现你这件事不能在截止时间前做完 top
那 么 就 去 堆 中 找 最 大 的 时 间 , 是 否 比 它 的 持 续 时 间 要 长 那么就去堆中找最大的时间,是否比它的持续时间要长
如 果 比 它 要 长 那 么 就 可 以 把 堆 中 的 那 件 事 替 换 成 这 件 事 如果比它要长那么就可以把堆中的那件事替换成这件事
由 于 是 替 换 , 结 果 是 不 变 的 , 而 且 由 于 是 按 截 止 时 间 排 序 由于是替换,结果是不变的,而且由于是按截止时间排序
那 件 事 比 他 截 止 时 间 早 , 持 续 时 间 长 都 可 以 做 完 堆 中 的 每 一 件 那件事比他截止时间早,持续时间长都可以做完堆中的每一件
你 让 在 做 那 件 事 的 时 候 做 现 在 新 替 换 的 事 , 仍 然 可 以 使 这 个 堆 成 立 你让在做那件事的时候做现在新替换的事,仍然可以使这个堆成立 使
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

struct node{
    ll s,t;
}p[maxn];
bool cmp(node a,node b){
    return a.t<b.t;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>p[i].s>>p[i].t;
    sort(p+1,p+1+n,cmp);
    priority_queue<int>q;
    ll sum=0,ans=0;
    for(int i=1;i<=n;i++){
        if(sum+p[i].s<=p[i].t){
            ans++;sum+=p[i].s;
            q.push(p[i].s);
        }
        else if(q.top()>p[i].s){
            sum-=q.top();q.pop();
            sum+=p[i].s;q.push(p[i].s);
        }
    }
    cout<<ans<<endl;
    return 0;
}

根据引用[1],dp[u][j]表示在u子树中选取恰好j个人时能获得的最大价值。而根据引用,该问题的时间复杂度为O(log2​104×nm)。 对于洛谷P2143 [JSOI2010] 巨额奖金问题,我们可以使用动态规划来解决。具体步骤如下: 1. 首先,我们需要构建一棵树来表示员工之间的关系。树的根节点表示公司的总经理,其他节点表示员工。每个节点都有一个权值,表示该员工的奖金金额。 2. 接下来,我们可以使用动态规划来计算每个节点的dp值。对于每个节点u,我们可以考虑两种情况: - 如果选择节点u,则dp[u][j] = dp[v][j-1] + value[u],其中v是u的子节点,value[u]表示节点u的奖金金额。 - 如果不选择节点u,则dp[u][j] = max(dp[v][j]),其中v是u的子节点。 3. 最后,我们可以通过遍历树的所有节点,计算出dp[u][j]的最大值,即为所求的巨额奖金。 下面是一个示例代码,演示了如何使用动态规划来解决洛谷P2143 [JSOI2010] 巨额奖金问题: ```python # 构建树的数据结构 class Node: def __init__(self, value): self.value = value self.children = [] # 动态规划求解最大奖金 def max_bonus(root, j): dp = [[0] * (j+1) for _ in range(len(root)+1)] def dfs(node): if not node: return for child in node.children: dfs(child) for k in range(j, 0, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-1] + node.value) for child in node.children: for k in range(j, 0, -1): for l in range(k-1, -1, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-l-1] + dp[child.value][l]) dfs(root) return dp[root.value][j] # 构建树 root = Node(1) root.children.append(Node(2)) root.children.append(Node(3)) root.children[0].children.append(Node(4)) root.children[0].children.append(Node(5)) root.children[1].children.append(Node(6)) # 求解最大奖金 j = 3 max_bonus_value = max_bonus(root, j) print("最大奖金为:", max_bonus_value) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值