1 条题解
-
0
这个问题要求计算安装所有软件包所需的最小介质更换次数。关键在于理解问题的本质,并将其转化为有效的算法。
问题分析
软件包分布在两张DVD上,安装过程需要遵循依赖关系,并且每次更换DVD都算一次操作。初始时驱动器为空,需要插入第一张DVD,结束时需要取出DVD,这两次也算作更换次数。
关键点:
- 依赖关系形成一个有向无环图(DAG)
- 每次只能安装同一DVD上的软件包,直到无法继续
- 必须从独立的软件包(入度为0)开始安装
- 目标是最小化更换DVD的次数
方法思路
通过分析,我们可以将问题转化为:在遵循依赖关系的前提下,如何安排DVD的使用顺序,使得更换次数最少。
算法思路:
- 使用拓扑排序处理依赖关系
- 维护两个队列,分别存储来自两张DVD的可安装软件包
- 每次尽可能多地安装同一DVD上的软件包,直到无法继续
- 切换到另一张DVD,重复上述过程
- 计算两种可能的初始DVD选择下的最小更换次数
解决代码
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <cstring> #include <queue> using namespace std; int d[100010], dd[100010], head[100010]; int cnt; int n1, n2; struct nod { int v; int nex; } edge[200010]; // 注意边的数量可能达到200000 queue<int> q[2]; void init() { cnt = 0; memset(head, -1, sizeof(head)); memset(dd, 0, sizeof(dd)); memset(d, 0, sizeof(d)); } void addEdge(int u, int v) { edge[cnt].v = v; edge[cnt].nex = head[u]; head[u] = cnt++; d[v]++; dd[v]++; } void deal() { while (!q[0].empty()) q[0].pop(); while (!q[1].empty()) q[1].pop(); for (int i = 1; i <= n1 + n2; i++) { if (d[i] == 0) { if (i <= n1) q[0].push(i); else q[1].push(i); } } } int fun(int k) { deal(); int ans = 0; while (!q[0].empty() || !q[1].empty()) { bool changed = false; while (!q[k].empty()) { int u = q[k].front(); q[k].pop(); changed = true; for (int i = head[u]; i != -1; i = edge[i].nex) { int v = edge[i].v; d[v]--; if (d[v] == 0) { if (v <= n1) q[0].push(v); else q[1].push(v); } } } if (changed) ans++; k ^= 1; } return ans; } int main() { int m; while (scanf("%d%d%d", &n1, &n2, &m) == 3) { if (n1 == 0 && n2 == 0 && m == 0) break; init(); int u, v; for (int i = 0; i < m; i++) { scanf("%d%d", &v, &u); addEdge(u, v); } int ans1 = fun(0); for (int i = 1; i <= n1 + n2; i++) { d[i] = dd[i]; } int ans2 = fun(1); int ans = min(ans1, ans2); cout << ans + 1 << endl; } return 0; }
代码解释
-
数据结构:使用邻接表存储图的结构,每个节点的入度用于拓扑排序。
-
初始化:
init()
函数初始化图的结构和入度数组。 -
添加边:
addEdge()
函数用于添加依赖关系,更新入度。 -
处理队列:
deal()
函数初始化两个队列,分别存储两张DVD上入度为0的软件包。 -
拓扑排序:
fun()
函数实现拓扑排序的核心逻辑,每次尽可能多地安装同一DVD上的软件包,直到无法继续,然后切换到另一张DVD。 -
主函数:读取输入,初始化图,计算两种初始DVD选择下的更换次数,并输出最小值加1(考虑初始插入和最终取出)。
通过这种方法,我们可以有效地计算出安装所有软件包所需的最小介质更换次数。
- 1
信息
- ID
- 779
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 1
- 上传者