题解 | #最强碰撞#

最强碰撞

https://www.nowcoder.com/practice/9796395a28494748b08840170af39216

题目链接

PEEK145 最强碰撞

题目描述

火星科研团队发现了 颗性质各异的原子,编号依次为 。他们可以任取其中两颗原子进行碰撞,碰撞后,其中一颗原子会消失并从系统中移除,同时产生一定的能量。这个过程会一直持续,直到只剩下一颗原子为止。

研究人员已经提前测得了任意两颗原子 发生碰撞,如果原子 消失,能够产生的能量为 。为了获得尽可能多的总能量,他们可以自由决定碰撞的顺序,以及每次碰撞中哪颗原子消失。你需要帮助研究人员设计碰撞顺序,使得所有 次碰撞产生的能量之和最大。

解题思路

这是一个寻找最优决策序列以获取最大收益的问题。观察到原子数量 的范围非常小(通常 ),这是使用状态压缩动态规划(State Compression DP)的典型信号。

我们的目标是记录一系列碰撞后获得的最大能量。一个碰撞过程可以用当前哪些原子“存活”或“消失”来描述。因此,我们可以用一个整数的二进制位来表示所有原子的状态集合。

状态定义

我们定义一个 DP 数组 ,其中 是一个 位的二进制数(位掩码),它的第 位为 表示第 颗原子已经消失,为 则表示第 颗原子仍然存在

的值就表示:在 所描述的原子消失集合下,可以获得的最大总能量。

状态转移

我们的目标是计算出所有可能的 。我们可以通过枚举当前状态,然后考虑下一步可能发生的碰撞来更新后续状态的值。这是一种“推”的 DP 思路。

假设我们当前处于状态 ,这意味着集合 中的原子已经消失了。此时,我们可以从仍然存在的原子中,任意挑选两颗,比如 (即 的第 位和第 位都为 ),让它们进行碰撞。

  1. 如果让原子 消失:

    • 系统获得能量
    • 状态将从 转移到一个新的状态 ,其中原子 也消失了。这个新状态 的位掩码就是
    • 我们用当前的总能量 来更新新状态的 DP 值。即:
  2. 同理,如果让原子 消失,状态会转移到 ,并获得能量

我们可以遍历所有当前状态 ,再遍历所有可能的碰撞组合 ,用上述方法更新所有可达的未来状态。

初始状态

  • 最开始时,没有任何原子消失,所以初始状态是 。此时的总能量为 ,即

最终答案

  • 整个过程会进行 次碰撞,最终会留下 颗原子,也就是有 颗原子消失。
  • 因此,最终的答案就是所有包含了 个消失原子(即二进制表示中有 )的状态 中, 的最大值。

整个算法的流程如下:

  1. 初始化 数组,设置 ,其余为
  2. 遍历所有状态
  3. 对于每个状态 ,遍历所有可能的原子对
  4. 如果原子 在状态 中都还存在,则模拟它们碰撞并分别计算两种消失情况( 消失或 消失)带来的能量增益,并更新对应的新状态的 值。
  5. 所有状态更新完毕后,遍历所有满足 的状态 ,找出其中最大的 值即为答案。

代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int n;
    while (cin >> n && n != 0) {
        vector<vector<int>> energy(n, vector<int>(n));
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                cin >> energy[i][j];
            }
        }

        vector<long long> dp(1 << n, 0);

        for (int s = 0; s < (1 << n); ++s) {
            for (int i = 0; i < n; ++i) {
                // 检查原子 i 是否存在
                if (!((s >> i) & 1)) {
                    for (int j = 0; j < n; ++j) {
                        // 检查原子 j 是否存在,且不与 i 相同
                        if (i != j && !((s >> j) & 1)) {
                            // i 与 j 碰撞,j 消失
                            int next_s = s | (1 << j);
                            dp[next_s] = max(dp[next_s], dp[s] + energy[i][j]);
                        }
                    }
                }
            }
        }

        long long max_energy = 0;
        for (int s = 0; s < (1 << n); ++s) {
            int set_bits = 0;
            for (int i = 0; i < n; ++i) {
                if ((s >> i) & 1) {
                    set_bits++;
                }
            }
            if (set_bits == n - 1) {
                max_energy = max(max_energy, dp[s]);
            }
        }
        cout << max_energy << endl;
    }
    return 0;
}
import java.util.Scanner;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n;
        while ((n = sc.nextInt()) != 0) {
            int[][] energy = new int[n][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    energy[i][j] = sc.nextInt();
                }
            }

            long[] dp = new long[1 << n];
            Arrays.fill(dp, 0);

            for (int s = 0; s < (1 << n); s++) {
                for (int i = 0; i < n; i++) {
                    // 检查原子 i 是否存在
                    if ((s & (1 << i)) == 0) {
                        for (int j = 0; j < n; j++) {
                            // 检查原子 j 是否存在,且不与 i 相同
                            if (i != j && (s & (1 << j)) == 0) {
                                // i 与 j 碰撞,j 消失
                                int nextS = s | (1 << j);
                                dp[nextS] = Math.max(dp[nextS], dp[s] + energy[i][j]);
                            }
                        }
                    }
                }
            }

            long maxEnergy = 0;
            for (int s = 0; s < (1 << n); s++) {
                if (Integer.bitCount(s) == n - 1) {
                    maxEnergy = Math.max(maxEnergy, dp[s]);
                }
            }
            System.out.println(maxEnergy);
        }
    }
}
import sys

for line in sys.stdin:
    n = int(line)
    if n == 0:
        break
    
    energy = []
    for _ in range(n):
        energy.append(list(map(int, sys.stdin.readline().split())))
        
    dp = [0] * (1 << n)
    
    for s in range(1 << n):
        for i in range(n):
            # 检查原子 i 是否存在
            if not ((s >> i) & 1):
                for j in range(n):
                    # 检查原子 j 是否存在,且不与 i 相同
                    if i != j and not ((s >> j) & 1):
                        # i 与 j 碰撞,j 消失
                        next_s = s | (1 << j)
                        dp[next_s] = max(dp[next_s], dp[s] + energy[i][j])
                        
    max_energy = 0
    for s in range(1 << n):
        if bin(s).count('1') == n - 1:
            max_energy = max(max_energy, dp[s])
            
    print(max_energy)

算法及复杂度

  • 算法:状态压缩动态规划
  • 时间复杂度:状态总数为 。对于每个状态,我们需要两层循环来枚举所有可能的碰撞原子对 ,这需要 的时间。因此,总时间复杂度为
  • 空间复杂度:我们需要一个 数组来存储所有状态的能量值,其大小为 。因此,空间复杂度为
全部评论

相关推荐

头像
04-27 15:11
已编辑
华东师范大学 算法工程师
暑期实习从2月开始投,面了两个月,流程该挂的都挂完了,腾讯字节一共号称是1.7w个hc,不知道都发给谁了,估计今年秋招要难顶。Timeline米哈游、美团、蚂蚁、微软等公司直接简历挂穿,没进面。携程:3.3&nbsp;投递、测评3.12&nbsp;笔试3.18&nbsp;一面3.25&nbsp;二面4.13&nbsp;ai面(hr面)4.14&nbsp;英语测评4.23&nbsp;offer(已拒)腾讯:2.6&nbsp;测评2.28&nbsp;wxg一面3.5&nbsp;wxg二面(挂)3.11&nbsp;teg一面3.21&nbsp;teg二面(取消)3.31&nbsp;teg一面4.10&nbsp;teg二面(挂)4.21&nbsp;wxg一面4.24&nbsp;wxg二面(挂)字节:1.28&nbsp;aml约面(取消)3.17&nbsp;火山一面(挂)4.8&nbsp;aml一面(挂)4.20&nbsp;抖音data一面(挂)阿里:3.23&nbsp;投递、测评3.28&nbsp;笔试3.31&nbsp;淘天一面4.8&nbsp;钉钉一面4.9&nbsp;淘天二面4.10&nbsp;阿里控股一面4.12&nbsp;钉钉二面(取消)4.15&nbsp;淘天hr面4.16&nbsp;淘天offer(已接)4.21&nbsp;高德一面(取消)4.22&nbsp;淘宝闪购一面(取消)面试最大的感触是,现在撞上ai转型,一堆老业务急着转向,新业务非常不成熟,研究型的组bar非常高根本进不去,业务侧挂着算法的岗位干的都是工程活,面试却又要问算法,另外agent的落地也远没有那么广,绝大多数还是那套写死的系统调一下llm&nbsp;api或者做做rag,其余少部分真的在搭agent的,基本不能在线上服务用什么很智能的模型,现阶段成本太高,进去大概率就是给垃圾模型从工程方面兜底,除了业务场景的应用和数据经验以外,技术方面很难有什么提升。算法岗做不了基模的还是去搜广推好,之前判断失误了完全没投,秋招不知道还进不进得去。
绿糖滑稽:携程这什么雷霆流程时长
我的求职进度条
点赞 评论 收藏
分享
03-27 01:58
已编辑
西北工业大学 Java
在平静中度过当下:如果这个bg也简历挂的话可能他们现在不缺人了吧,我也是这两天投的,阿里和快手投的岗都是简历秒挂
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务