楼主: lesheng66
206 0

[学校简介] [CSP-S 2025] 道路修复 题解 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

40%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
20 点
帖子
1
精华
0
在线时间
0 小时
注册时间
2018-7-7
最后登录
2018-7-7

楼主
lesheng66 发表于 2025-11-24 15:18:59 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

C 国的交通网络由 n 座城市和 m 条双向道路构成,每条道路连接两座城市。第 i 条道路(1 ≤ i ≤ m)连接城市 ui 与 vi。整个交通系统是连通的,任意两个城市之间都可以通过若干道路相互抵达。

然而,一场大地震导致所有 m 条道路全部损毁。修复第 i 条道路需要花费 wi 的费用。此外,C 国还有 k 个待进行城市化改造的乡镇。对第 j 个乡镇(1 ≤ j ≤ k)实施城市化改造需支出 cj 的成本。一旦完成改造,便可从该乡镇向原有的 n 座城市分别修建新道路。其中,从第 j 个乡镇到第 i 座城市(1 ≤ i ≤ n)修建一条道路的成本为 aj,i

政府可以选择任意数量的乡镇进行城市化改造,也可以一个都不选。目标是以最低总成本确保原有的 n 座城市之间实现两两连通——即任意两座原城市可以通过修复或新建的道路路径互相到达。

你的任务是计算出达成这一目标所需的最小总费用。

输入格式

第一行包含三个非负整数 n、m 和 k,分别表示原始城市的数量、道路总数以及可进行城市化改造的乡镇数目。

接下来的 m 行中,第 i 行(1 ≤ i ≤ m)给出三个非负整数 ui、vi、wi,描述第 i 条道路所连接的城市及其修复开销。

随后的 k 行中,第 j 行(1 ≤ j ≤ k)包含 n + 1 个非负整数:cj 后跟 aj,1, aj,2, ..., aj,n,依次表示对第 j 个乡镇进行城市化改造的费用,以及从该乡镇通往各原始城市的道路建设费用。

输出格式

输出一行,包含一个非负整数,代表使原有 n 座城市完全连通的最低总成本。

样例输入 #1

4 4 2
1 4 6
2 3 7
4 2 5
4 3 4
1 1 8 2 4
100 1 3 2 4

样例输出 #1

13

样例解释

一种可行方案为:修复第 3 条和第 4 条道路,并对第 1 个乡镇实施城市化改造,随后在其与第 1 和第 3 号城市之间新建道路。总费用为 5 + 4 + 1 + 1 + 2 = 13。可以证明,不存在低于 13 的方案能够实现四座原始城市的全连通。

其他样例说明

样例 2 对应文件目录下的 road/road2.in 与 road/road2.ans,符合测试点 11 和 12 的限制条件。

样例 3 对应文件目录下的 road/road3.in 与 road/road3.ans,适用于测试点 13 和 14 的情况。

样例 4 对应文件目录下的 road/road4.in 与 road/road4.ans,满足测试点 15 和 16 的数据约束。

数据范围

对于所有测试用例:

  • 1 ≤ n ≤ 10
  • 1 ≤ m ≤ 10
  • 0 ≤ k ≤ 10
  • 对于所有 1 ≤ i ≤ m,有 1 ≤ ui, vi ≤ n,ui ≠ vi,且 0 ≤ wi ≤ 10
  • 对于所有 1 ≤ j ≤ k,有 0 ≤ cj ≤ 10
  • 对于所有 1 ≤ j ≤ k 和 1 ≤ i ≤ n,有 0 ≤ aj,i ≤ 10

对于满足条件的整数范围:1 ≤ i ≤ n 且 1 ≤ j ≤ k,均有 0 ≤ aj,i ≤ 109;同时,任意两座原始城市之间都可以通过若干条已有的道路相互连通。

::cute-table{tuack}
测试点编号 n ≤ m ≤ k ≤ 特殊性质
1~4 104 106 0
5, 6 103 105 5 A
7, 8 ^ ^ ^
9, 10 ^ 106 ^ A
11, 12 ^ ^ ^
13, 14 ^ ^ 10 A
15, 16 ^ ^ ^
17, 18 104 ^ 5 A
19, 20 ^ ^ ^
21~25 ^ ^ 10 ^

特殊性质 A 的定义如下:对所有 1 ≤ j ≤ k,均有 cj = 0,并且存在至少一个 1 ≤ i ≤ n,使得 aj,i = 0 成立。

题解思路

根据题目描述,可以初步设计出一种暴力解法,能够获得 64 分。具体做法是枚举每个乡村是否被选中的 2k 种状态,在每种状态下构建对应的图并运行最小生成树(MST)算法。该方法的时间复杂度为 O(2k(m + nk) log(m + nk))。

进一步观察 MST 的一个关键性质:若某条边在原图的 MST 中未被选用,则在向图中添加新边后,这条边也不会出现在新的 MST 中。基于这一性质,我们可以先对原始城市的道路网络单独运行一次 MST 算法,从而将原图的边数压缩至 O(n) 级别。

在此基础上再进行乡村加入状态的枚举,此时每次 MST 计算的规模显著减小。优化后的总时间复杂度约为 O(2knk log nk log n),若提前对边排序,则可进一步降低为 O(2knk log n),此版本可得 80 分。

为了达到满分,需引入两个关键剪枝策略:

  • 将城市的权重标记为 1,乡村标记为 0;当某个连通块内权重总和等于 n 时,说明所有城市已被连接,即可提前终止计算。
  • 加入最优性剪枝,并将并查集中的递归查找改为迭代实现,以提升效率并避免深层递归带来的开销。

经过上述优化后,算法能够在规定时间内通过全部测试点,获得 100 分。

参考代码结构说明

代码采用 C++ 实现,核心部分包括边结构体定义、并查集操作、Kruskal 算法封装以及主状态枚举逻辑。使用了高效的输入处理和容器管理方式,确保在大规模数据下仍具备良好性能。

4 4 2
1 4 6
2 3 7
4 2 5
4 3 4
1 1 8 2 4
100 1 3 2 4

主要变量说明:

  • e[N], b[N]:存储原始边与扩展边;
  • head[N], nxt[N]:链式前向星存图结构;
  • f[N]:并查集父节点数组;
  • sss[N]:记录各连通块所包含的城市数量;
  • c[k], a[k][N]:分别表示乡村建设代价及连接信息;
  • mp:用于映射节点编号;
  • ss:保存参与 MST 构建的有效边索引集合。

函数功能简述:

  • add():向邻接表中插入一条边;
  • find():带路径压缩的并查集查找函数;
  • kruskal(int x):根据当前乡村选择状态 x 执行 MST 构造;
  • read():快速读入整数。
13
int x = 0;
while(ch < 48 || ch > 57) ch = getchar();
while(48 <= ch && ch <= 57)
{
    x = (x << 1) + (x << 3) + ch - 48;
    ch = getchar();
}
return x;
}

int main()
{
    freopen("road.in", "r", stdin);
    freopen("road.out", "w", stdout);
    n = read(), m = read(), k = read();
    for(int i = 1; i <= m; ++i)
        e[i].u = read(), e[i].v = read(), e[i].w = read(), e[i].id = -1;

    vector<int> av;
    for(int i = 1; i <= m; ++i)
        av.pb(e[i].w);

    int tmp = 0;
    for(int i = 0; i < k; ++i)
    {
        c[i] = read();
        tmp = max(tmp, c[i]);
        for(int j = 1; j <= n; ++j)
            av.pb(a[i][j]);
    }

    sort(av.begin(), av.end());
    av.erase(unique(av.begin(), av.end()), av.end());

    int tot = 0;
    for(int val : av)
        mp[val] = ++tot;

    for(int i = 1; i <= n; ++i)
        f[i] = i;

    sort(e + 1, e + 1 + m);
    for(int i = 1; i <= m; ++i)
    {
        int fu = find(e[i].u), fv = find(e[i].v);
        if(fu == fv) continue;
        int pos = mp[e[i].w];
        add(pos, e[i]);
        ss.pb(pos);
        f[fu] = fv;
    }

    for(int i = 0; i < k; ++i)
    {
        for(int j = 1; j <= n; ++j)
        {
            int pos = mp[a[i][j]];
            add(pos, (node){n + i + 1, j, a[i][j], i});
            ss.pb(pos);
        }
    }

    sort(ss.begin(), ss.end());
    ss.erase(unique(ss.begin(), ss.end()), ss.end());

    if(!tmp)
    {
        cout << kruskal((1 << k) - 1);
        return 0;
    }

    ll ans = 1e18;
    for(int i = 0; i < (1 << k); ++i)
        ans = min(ans, kruskal(i));

    cout << ans;
    return 0;
}
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:道路修复 CSP Kruskal while Table

院校老师推荐 一对一咨询 帮你科学报考 更多...
  • 杜**-上海交通大学-公共卫生学院
    杜**黄浦区
    其他评分:5.0
    学校:上海交通大学-公共卫生学院
    研究领域:公共卫生
    立即咨询
  • 戴稳胜-中国人民大学-财政金融学院
    戴稳胜北京市
    博导评分:1.0
    学校:中国人民大学-财政金融学院
    研究领域:风险管理、保险精算、人民币国际化
    立即咨询
  • 张千帆-哈尔滨工业大学-电气工程及自动化学院
    张千帆哈尔滨市
    博导评分:5.0
    学校:哈尔滨工业大学-电气工程及自动化学院
    研究领域:电气工程,新能源汽车驱动和充电
    立即咨询
  • 万志宏-南开大学-经济学院
    万志宏天津市
    硕导评分:5.0
    学校:南开大学-经济学院
    研究领域:国际金融、金融市场
    立即咨询
  • 陈传红-中南民族大学-管理学院
    陈传红武汉市
    硕导评分:5.0
    学校:中南民族大学-管理学院
    研究领域:数字经济与消费行为,共享经济与协同消费,创新与采纳行为
    立即咨询
  • 何斌锋-南京大学-终身教育学院
    何斌锋苏州市
    其他评分:5.0
    学校:南京大学-终身教育学院
    研究领域:技术经济学、文化经济学
    立即咨询
您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-5 18:25