引爆炸弹
贪心
【问题描述】
有 n 个炸弹,有些炸弹牵了一根单向引线(也就是说引线只有在这一端能被炸弹点燃),只要引爆了这个炸弹,用引线连接的下一个炸弹也会爆炸。每个炸弹还有个得分,当这个炸弹被引爆后就能得到相应得分。现在要你引爆 k 个炸弹,使得得分最大。
【输入】
第一行两个整数 n、k。
接下来的 n 行,每行两个整数 a[i]、b[i]。a[i]表示这个炸弹用引线连接的下一个炸弹,如果a[i]为 0,则表示这个炸弹没有连接引线。b[i]表示这个炸弹的得分。
【输出】
最大得分。
【数据规模】
1≤b[i]≤1000000
对于 30%的数据,n≤1000,k≤30;
对于 60%的数据,n≤50000,k≤100;
对于 100%的数据,n≤200000,k≤500。
【解题过程】
题目给出的是一棵树(注意其实有可能是环,题目并没有明说,但是理论上来讲最好要先用 Tarjan 缩点然后编程复杂度就呵呵,而其实题目的所有数据中并没有出现环),很明显应该引爆叶节点。所以我们就计算出引爆每个叶节点能得到的最大分数。但是两个叶节点往后的路径可能会重叠,这时应该将后面的那些节点分配给能够得到较大分数的那个叶节点。怎么知道哪个叶节点更「划算」?我们可以先遍历一遍图,维护每个节点的一个 v 值,v(i) = max{ v(j)+b(i), <j, i>∈E },并用 from(i) 记录下从哪个点转移过来是最大值。然后再遍历一遍图,对于一个结点 i,用 f(i) 表示从它开始引爆能够得到的最大得分,如果它相连的结点 j 的 from 不是 i,那么 f(i) = b(i),否则 f(i) 等于 b(i)+f(j)。最后根据 f 值排序取前 k 个。
注意图的遍历最好用 BFS,DFS 可能会爆栈(但是貌似实际上不会?)。
第一次提交 AC。
取石子
贪心
【问题描述】
有 n 个石子围成一圈,每个石子都有一个权值 a[i]。给你一次且仅一次取石子的机会,取石子的块数不限,取完后统计得分。现在要使取出的石子得分最大。
每个石子的得分计算公式是 a[i]*d,d 表示这个石子到两边被取了的石子的距离和。如{1,2,7,9,8,6,4,5,3,10}这些权值的石子围成一圈,不同取法有不同得分:
【输入】
第一行一个整数 n。
接下来 n 行,每行一个整数 a[i]。
【输出】
仅一个整数,表示最大得分。
【输入样例】
5
1
2
3
4
20
【输出样例】
80
【数据规模】
1≤a[i]≤100000
对于 30%的数据,n≤60;
对于 60%的数据,n≤300;
对于 100%的数据,n≤100000。
【解题过程】
其实一开始有直觉感觉好像取两个的时候就是最大的,但是想想不太靠谱就往RMQ+贪心去想了。大致就是每次在分隔出的几个区间中找权值最大的点判断取了这个点之后解是否更优,如果是就取,然后继续贪心;否则当前就是最大值。
然后 WJZ 大神说取两个一定比取两个以上更优,而且给出了证明(orz)。其实再想想发现肯定是对的。取两个数字当然是取最大的那两个数字,那么在区间中如果再取一个数字,这个数字不会大于已经取了的两个数字,但是计算距离的时候由于多了一个障碍点距离也就少了1,变得更差了。
但是注意取两个不一定比取一个更优,所以要看这两种情况哪种更优。
注意要 long long。以及找最大的两个值的时候写错了。
我是这样写的
if a[i] > max
max2 = max
max = a[i]
还能逗逼更多么?
化工厂装箱员
动态规划
【输入样例】
11
A
B
C
A
B
C
A
B
C
A
B
【输出样例】
3
【解题过程】
首先看题目花了很久。
然后果断搜索了。看前两题贪心以为今天贪心专场,然后没有想到这道题的正确贪心方法,后来才知道不是贪心。
有一个显而易见的但是错的贪心方法:将目前手中数目最多的那种物品先装箱。能过 7 个点。
正解是动规:
用 f(i, A, B, C) 表示已经前 i-1 个物品已经取出,而当前的 10 个物品中,A 类物品有 A 个,以此类推。则
f(i, A, B, C) = max{ f(i+A, A', B, C), f(i+B, A, B', C), f(i+C, A, B, C') }
其中 f(i+A, A', B, C) 表示将 10 个物品中的 A 物品全部装箱了,而 A' 表示接下来从流水线取出的 A 个物品中有多少个 A 类物品,其他两个表达式是类似的意思。
第一次提交 20 分。搜索都能写错我也是醉了。后来先做了一次贪心作为初始较优解来剪枝还是只能过 7 个点。动规大法好。