1 条题解
-
0
题目概述
有 个黑帮首领,每人持枪瞄准另一个首领(可能是自己)。如果发生枪战,规则如下:
- 按某个顺序依次开枪,每人只能开一枪
- 被击中者立即死亡,无法开枪
- 即使目标已死,也必须向原目标开枪(但不会增加死亡人数)
- 不能改变瞄准目标
需要计算在所有可能的开枪顺序下,死亡人数的最小值和最大值。
问题分析
关键观察
- 图论模型:将首领看作点,瞄准关系看作有向边,形成功能图(每个点出度为1)
- 环与链:功能图由若干环和连向环的链组成
- 死亡条件:一个首领死亡当且仅当:
- 他被某人击中(在开枪顺序中,瞄准他的人先于他开枪)
- 或者他瞄准的人已死,他必须对尸体开枪(浪费子弹)
问题转化
我们需要找出在所有可能的开枪顺序下:
- 最少会有多少人死亡
- 最多会有多少人死亡
算法思路
步骤1:拓扑排序处理链部分
对于不在环上的点(即入度为0的点):
- 它们构成指向环的链
- 这些点一定不会死(因为没人瞄准它们)
- 但它们可能会杀死环上的点
步骤2:处理环
环是问题的核心。对于每个环:
- 最大死亡人数:环上所有人都可能死
- 最小死亡人数:需要精心安排开枪顺序来尽量减少死亡
具体算法
数据结构
s[i]:首领 瞄准的目标indeg[i]:入度,用于拓扑排序vis1[i]:标记是否在最小死亡方案中死亡vis2[i]:标记是否在最大死亡方案中死亡
拓扑排序 (
toposort)void toposort() { queue<int> q; // 入度为0的点入队(链的起点) for (int i = 1; i <= n; i++) if (indeg[i] == 0) q.push(i); while (!q.empty()) { int u = q.front(), v = s[u]; q.pop(); if (!vis1[u]) vis1[v] = true; // u没死,v会死(最小方案) vis2[v] = true; // v会死(最大方案) if (--indeg[v] == 0) q.push(v); } }拓扑排序的作用:
- 处理所有链上的点
- 确定链上点对环上点的影响
环处理 (
solve)对于每个环:
void solve(int p) { // 自环特判 if (s[p] == p) { vis1[p] = vis2[p] = true; return; } // 第一遍遍历:找到关键点,标记vis2 int tmp = p, pos = vis1[p] ? p : 0; p = s[p]; while (p != tmp) { indeg[p] = 0; if (vis1[p]) pos = p; if (vis2[p]) vis2[tmp] = true; vis2[p] = true; p = s[p]; } // 第二遍遍历:确定最小死亡方案 if (pos) p = pos; bool flag = !vis1[p]; tmp = p, p = s[p]; while (p != tmp) { if (vis1[p]) flag = false; else if (flag) { vis1[p] = true; flag = false; } else flag = true; p = s[p]; } if (flag) vis1[p] = true; }最小死亡人数的策略
在环上,我们可以通过精心安排开枪顺序来救一些人:
- 如果环长 为奇数:最少死亡 人
- 如果环长 为偶数:最少死亡 人
- 但还要考虑链对环的影响
最大死亡人数的策略
在环上,最坏情况下所有人都可能死亡:
- 安排开枪顺序使得每个活着的人都要对尸体开枪
- 但有些点可能因为链的影响而必死或必活
样例解析
样例输入
8 2 3 2 2 6 7 8 5瞄准关系:1→2, 2→3, 3→2, 4→2, 5→6, 6→7, 7→8, 8→5
图结构:
- 环1:2↔3(长度2)
- 环2:5→6→7→8→5(长度4)
- 链:1→2, 4→2
计算结果
- 最小死亡:3人
- 最大死亡:5人
验证:
- 最小:可以救环2中的2人,环1中的1人
- 最大:环上所有人都可能死,加上部分链上点
复杂度分析
- 时间复杂度:
- 拓扑排序:每个点入队一次
- 环处理:每个环遍历两次
- 空间复杂度:
- 存储图和相关数组
算法亮点
- 图论建模:将问题转化为功能图分析
- 分离处理:分别处理链和环的部分
- 贪心策略:在环上通过交替选择来最小化死亡
- 拓扑排序:高效处理链对环的影响
总结
这道题的核心在于理解功能图的结构,并分别处理链和环:
- 链处理:拓扑排序确定链上点的生死和它们对环的影响
- 环处理:精心安排开枪顺序来最小化死亡人数
- 最大死亡:考虑最坏情况下的开枪顺序
- 高效算法:线性时间解决大规模数据
这种"功能图分析 + 环链分离"的思路在解决依赖关系问题时非常有效,特别是在每个点只有单一出边的情况下。
- 1
信息
- ID
- 4860
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者