当前位置: 首页 > ds >正文

《CF1245D Shichikuji and Power Grid》

题目描述

Shichikuji 是南黑蜗牛寺的新任驻守神明。她的第一项工作如下:

在 X 县有 n 个新城市。城市编号从 1 到 n。第 i 个城市位于距离神社北方 xi​ 千米、东面 yi​ 千米的位置。可能存在 i=j 但 (xi​,yi​)=(xj​,yj​) 的情况。

Shichikuji 必须为每个城市供电,可以通过在该城市建造发电站,或者将该城市与已经有电的城市连接来实现。也就是说,如果一个城市自身有发电站,或者通过直接连接或一系列连接与有电的城市相连,则该城市就有电。

  • 在第 i 个城市建造发电站的费用为 ci​ 日元;
  • 将第 i 个城市与第 j 个城市连接的费用为每千米 (ki​+kj​) 日元。电线只能沿着正北、正南、正东、正西方向铺设,电线可以相互交叉。每根电线的两个端点都必须在某个城市。如果第 i 个城市与第 j 个城市连接,则电线会沿任意一条最短路径铺设。因此,连接第 i 个城市与第 j 个城市所需电线的长度为 ∣xi​−xj​∣+∣yi​−yj​∣ 千米。

Shichikuji 希望以尽可能少的钱完成这项工作,因为在她看来,世界上除了钱什么都没有。然而,她小学五年级就去世了,所以她还不够聪明。因此,这位新任驻守神明向你寻求帮助。

你需要为 Shichikuji 提供以下信息:为所有城市供电所需的最小日元数、在哪些城市建造发电站,以及需要建立哪些连接。

如果存在多种选择城市和连接方式使得总花费最小,则输出任意一种即可。

输入格式

输入的第一行包含一个整数 n(1≤n≤2000),表示城市的数量。

接下来 n 行,每行包含两个用空格分隔的整数 xi​(1≤xi​≤106)和 yi​(1≤yi​≤106),表示第 i 个城市的坐标。

下一行包含 n 个用空格分隔的整数 c1​,c2​,…,cn​(1≤ci​≤109),表示在第 i 个城市建造发电站的费用。

最后一行包含 n 个用空格分隔的整数 k1​,k2​,…,kn​(1≤ki​≤109)。

输出格式

第一行输出一个整数,表示为所有城市供电所需的最小日元数。

第二行输出一个整数 v,表示需要建造发电站的城市数量。

第三行输出 v 个用空格分隔的整数,表示建造发电站的城市编号。每个编号应在 1 到 n 之间,且互不相同。编号顺序任意。

接下来一行输出一个整数 e,表示需要建立的连接数量。

最后输出 e 行,每行包含两个整数 a 和 b(1≤a,b≤n,a=b),表示需要在城市 a 和城市 b 之间建立连接。每对无序城市对最多出现一次(即对于每个 (a,b),不应有重复的 (a,b) 或 (b,a))。输出顺序任意。

如果存在多种选择城市和连接方式使得总花费最小,则输出任意一种即可。

显示翻译

题意翻译

输入输出样例

输入 #1复制

3
2 3
1 1
3 2
3 2 3
3 2 3

输出 #1复制

8
3
1 2 3 
0

输入 #2复制

3
2 1
1 2
3 3
23 2 23
3 2 3

输出 #2复制

27
1
2 
2
1 2
2 3

说明/提示

对于样例给出的答案,可参考下图(绿色为有发电站的城市,蓝色为其他城市,红色为电线):

对于第一个样例,在所有城市建造发电站的总费用为 3+2+3=8。可以证明,没有任何方案的花费低于 8 日元。

对于第二个样例,在第 2 号城市建造发电站的费用为 2。连接城市 1 和城市 2 的费用为 2⋅(3+2)=10。连接城市 2 和城市 3 的费用为 3⋅(2+3)=15。因此总费用为 2+10+15=27。可以证明,没有任何方案的花费低于 27 日元。

由 ChatGPT 4.1 翻译

代码实现:

#include <bits/stdc++.h>
using namespace std;

const int MAX_NODE = 2005;  // 最大节点数量

// 快速输入结构体
struct FastInput {
    template <typename Type>
    FastInput & operator >> (register Type & value) {
        register int sign = 1; 
        value = 0; 
        register char ch = getchar();
        
        // 处理符号
        for (; !isdigit(ch); ch = getchar()) {
            if (ch == '-') sign = -sign;
        }
        
        // 处理数字
        for (; isdigit(ch); ch = getchar()) {
            value = (value << 1) + (value << 3) + (ch - '0');
        }
        
        value *= sign; 
        return *this;
    }
} input;

int totalNodes;               // 总节点数量
int powerStationCount;        // 直接建立电源的节点个数
long long costFactor[MAX_NODE];// 每个节点的代价因子K
long long xCoord[MAX_NODE];   // 节点的X坐标
long long yCoord[MAX_NODE];   // 节点的Y坐标
long long prevNode[MAX_NODE]; // 记录上一次更新该节点的节点,用于构建边
long long totalCost;          // 最后的总代价
long long minDist[MAX_NODE];  // 当前树到各个非树节点的最小代价
bool inTree[MAX_NODE];        // 记录节点是否已加入树中

int main() {
    input >> totalNodes;
    
    // 读取节点坐标
    for (register int i = 1; i <= totalNodes; i++) {
        input >> xCoord[i] >> yCoord[i];
    }
    
    // 读取直接建立电站的代价,初始化最小距离数组
    for (register int i = 1; i <= totalNodes; i++) {
        input >> minDist[i];
    }
    
    // 读取代价因子,初始化前置节点为0(表示直接连接电源)
    for (register int i = 1; i <= totalNodes; i++) {
        input >> costFactor[i];
        prevNode[i] = 0;
    }
    
    // Prim算法构建最小生成树
    for (register int step = 1; step <= totalNodes; step++) {
        // 寻找未加入树且距离最小的节点
        register long long minCost = 2147483640;
        register int selectedNode;
        
        for (register int i = 1; i <= totalNodes; i++) {
            if (!inTree[i] && minDist[i] < minCost) {
                minCost = minDist[i];
                selectedNode = i;
            }
        }
        
        // 将选中的节点加入树中
        inTree[selectedNode] = true;
        totalCost += minCost;
        
        // 如果前置节点是0,说明这是一个新的电站
        if (prevNode[selectedNode] == 0) {
            powerStationCount++;
        }
        
        // 更新其他节点到树的最小距离
        for (register int i = 1; i <= totalNodes; i++) {
            if (!inTree[i]) {
                // 计算连接到选中节点的代价
                long long connectionCost = (costFactor[i] + costFactor[selectedNode]) * 
                                         (abs(xCoord[selectedNode] - xCoord[i]) + 
                                          abs(yCoord[selectedNode] - yCoord[i]));
                
                // 如果新的连接代价更小,则更新
                if (minDist[i] > connectionCost) {
                    minDist[i] = connectionCost;
                    prevNode[i] = selectedNode;
                }
            }
        }
    }
    
    // 输出结果
    printf("%lld\n%d\n", totalCost, powerStationCount);
    
    // 输出建立电站的节点
    for (register int i = 1; i <= totalNodes; i++) {
        if (prevNode[i] == 0) {
            printf("%d ", i);
        }
    }
    printf("\n");
    
    // 输出边的数量和具体边
    printf("%d\n", totalNodes - powerStationCount);
    for (register int i = 1; i <= totalNodes; i++) {
        if (prevNode[i] != 0) {
            printf("%lld %d\n", prevNode[i], i);
        }
    }
    
    return 0;
}
 

http://www.xdnf.cn/news/18671.html

相关文章:

  • 嵌入式学习 day57 驱动-驱动框架
  • 国产CANFD芯片技术特性与应用前景综述:以ASM1042系列为例
  • Java试题-选择题(14)
  • 番茄(西红柿)叶片病害检测数据集:12k+图像,10类,yolo标注
  • 2025-08-22 Python进阶10——魔术方法
  • 从原理到实践:朴素贝叶斯算法的魅力解析
  • 构建城市数字孪生底座:深度解析智慧城市全景视频拼接融合解决方案
  • ingress和service区别
  • 未来已来?AI 预测技术在气象、金融领域的应用现状与风险警示
  • python3GUI--Joy音乐播放器 在线播放器 播放器 By:PyQt5(附下载地址)
  • Java面试-== 和 equals() 方法的区别与实现原理
  • Unreal Engine UE_LOG
  • 电脑芯片大的32位与64位指的是什么
  • 【数据结构】B+ 树——高度近似于菌丝网络——详细解说与其 C 代码实现
  • 面向RF设计人员的微带贴片天线计算器
  • AI领域的语义空间是什么?
  • ES6变量与解构:let、const与模板字符串全解析
  • 「越短越合法」型滑动窗口
  • 解释一下,Linux,shell,Vmware,Ubuntu,以及Linux命令和shell命令的区别
  • 111、【OS】【Nuttx】【周边】效果呈现方案解析:-print0 选项
  • Linux操作系统编程——网络
  • 第二阶段WinFrom-6:文件对话框,对象的本地保存,序列化与反序列化,CSV文件操作,INI文件读写
  • 08.21总结
  • Claude Code 三类.md文件
  • Day2--HOT100--283. 移动零,11. 盛最多水的容器,15. 三数之和
  • PCB电路设计学习2 元件原理图封装的添加 手工设计元件封装
  • 大型前端项目如何实现css 隔离:利用浏览器原生的 Shadow DOM 完全隔离 DOM 结构与样式...
  • Linux 下的网络编程
  • 学习嵌入式的第二十四天——数据结构——队列和树
  • Git 提交除某个文件外的其他所有文件