首页 > 其他分享 >abc270_f Transportation 题解

abc270_f Transportation 题解

时间:2023-05-17 23:56:07浏览次数:56  
标签:Transportation int 题解 城市 聚集地 建图 abc270 机场 ll

Transportation

题意

有 \(n\) 个城市,你可以执行以下操作若干次:

  • 选择一个没有建机场的城市 \(i\),花费 \(x_i\) 建一个机场。
  • 选择一个没有建港口的城市 \(i\),花费 \(y_i\) 建一个港口。

还有 \(m\) 条没有修建的道路,第 \(i\) 条道路双向连接 \(a_i\) 和 \(b_i\),修建这条道路需要花费 \(z_i\)。

两个城市 \(u\) 和 \(v\) 直接可达当且仅当:

  • \(u\) 和 \(v\) 都有机场。
  • \(u\) 和 \(v\) 都有港口。
  • \(u\) 和 \(v\) 直接有一条道路。

求最小花费,使得从任意一个城市 \(u\) 可以在经过若干城市后抵达任意一个城市 \(v\)。

思路

这题只考建图和最小生成树。

初步考虑

首先,不看机场和港口,那么就变成了一个最小生成树问题。

特殊情况

那么有机场呢?画张草图看看吧。

上面那种建图方式,就是在两个有机场的城市间建边,不仅难以维护花费,你也不知道有多少个城市建了机场,建图方式不够优秀。

优化建图

这种建图方式值得思考。

根据题意,两个有机场的城市可以互相抵达,相当于有一个机场聚集地,设立机场的城市可以来到这个聚集地,并从这里走向另外一个设立机场的城市。

那么维护起来就很方便了,假定机场聚集地在 \(n+1\),那么就可以把 \(i = 1,2\cdots n\) 中的每个 \(i\) 都向 \(n + 1\) 建立一条候选边,边权为 \(x_i\)。

上图就会变成:

港口同理,将聚集地设置为与机场聚集地不同的一个即可(也不能和任何一座城市下标相同),建议设为 \(n+2\)。

最后思考

可我并不知道是否要通过建立机场来互相抵达啊?

这个也不难,枚举是否建立机场和是否建立港口,跑一遍克鲁斯卡尔,求出 \(4\) 种情况中花费最小值即可。

复杂度

  • 时间:\(O(4\times(2n+m) \log (2n+m))\)。
  • 空间:\(O(2n+m)\)。

Code

#include <iostream>
#include <algorithm>

using namespace std;
using ll = long long;

const int N = 2e5 + 10, E = 6e5 + 10;

struct Edge {
  int x, y, z;
  bool operator < (const Edge &i) const {
    return z < i.z;
  }
} e[N], a[E];

int n, m, x[N], y[N], fa[N], ae;
ll ans = 1e18;

int Find (int x) {
  return (fa[x] ? fa[x] = Find(fa[x]) : x);
}

ll kruskal (bool f1, bool f2) { // 克鲁斯卡尔算法
  ll sum = 0;
  int num = 0;
  sort(a + 1, a + ae + 1);
  for (int i = 1; i <= ae; i++) { // 这些不用说了吧
    int l = Find(a[i].x), r = Find(a[i].y);
    if (l != r) {
      sum += a[i].z, num++, fa[l] = r;
    }
  }
  if (num == n + f1 + f2 - 1) { // 注意!题目并不保证在只走普通道路的情况下一定合法,需判断
    return sum;
  }
  return 1e18;
}

int main () {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> x[i];
  }
  for (int i = 1; i <= n; i++) {
    cin >> y[i];
  }
  for (int i = 1; i <= m; i++) {
    cin >> e[i].x >> e[i].y >> e[i].z;
  }
  for (int i = 0; i < 2; i++) { // 是否建立机场
    for (int j = 0; j < 2; j++) { // 是否建立港口
      for (int k = 1; k <= n + 2; k++) {
        fa[k] = 0; // 先清空
      }
      ae = 0;
      for (int k = 1; k <= m; k++) { // m 条道路
        a[++ae] = e[k];
      }
      if (i) { // 走机场
        for (int k = 1; k <= n; k++) {
          a[++ae] = {k, n + 1, x[k]};
        }
      }
      if (j) { // 走港口
        for (int k = 1; k <= n; k++) {
          a[++ae] = {k, n + 2, y[k]};
        }
      }
      ans = min(ans, kruskal(i, j));
    }
  }
  cout << ans;
  return 0;
}

标签:Transportation,int,题解,城市,聚集地,建图,abc270,机场,ll
From: https://www.cnblogs.com/lw0-blog/p/17410723.html

相关文章

  • CF1077E Thematic Contests 题解
    ThematicContests题意有\(n\)个问题,每个问题有一个分类\(a_i\)。现在要举办一些比赛,要求:一场比赛中所有题目的分类相同。所有比赛的分类是互不相同的。第一场比赛的题目数量任意,但从第二场开始,每一场比赛的题目数量都必须是前一场的两倍。求所有比赛的题目数量之和的......
  • abc235_d Multiply and Rotate 题解
    MultiplyandRotate题意给定两个整数\(a\)和\(n\),有一个整数\(x\),初始值为\(1\),有两种操作:将\(x\)变成\(x\timesa\)。在\(x>10\)且\(x\)不是十的倍数的情况下可以执行此操作:将\(x\)当成一个字符串,将其循环右移一次。求最少执行多少次操作能把\(x\)变......
  • P8786 李白打酒加强版 题解
    李白打酒加强版题目大意一开始酒显里有\(2\)斗酒,每遇到一次店就会把酒显里的酒数量(单位:斗)乘\(2\),每遇到一次花就把酒显里的酒喝掉\(1\)斗。这一路上一共遇到店\(n\)次,遇到花\(m\)次,且最后一次遇到的是花,酒显里没有一斗酒了。计算这一路上遇到店和花的顺序总共有......
  • YACS 2023年5月月赛 甲组 T1 子集和(六) 题解
    YACS老师说这是道分治,但就不告诉我怎么做,我硬是用线段树卡了过去...特别解气的是把AC图片发了过去(我就是在YACS上的编程课)莫队好了说点正经的,看到是谁谁谁的倍数就能想到DP,状态设计也很水啦!设f[i]为当前考虑到的区间内,子集和%k=i的数量。新加入一个元素时,循环0~......
  • CF1183C Computer Game 题解
    ComputerGame还算水的一道题。题意本题意为题面直接翻译的简化版,可能会比题目翻译要复杂。有\(q\)次询问,每次给出四个数,表示一开始的电亮为\(k\),有\(n\)个回合,不插电玩一个回合则电量会减少\(a\),插电玩一个回合则电量会减少\(b\),电量在任何时刻都必须严格大于\(0\)......
  • Plsql或Navicat连接登陆Oracle时慢、执行语句的时候也特别慢的问题解决方案
    用Plsql或Navicat连接登陆Oracle时,等待时间特别长。经过漫长的等待后,执行语句的时候也特别慢,监听配置没毛病的情况下,大概率是监听日志文件过大导致的。监听日志路径:app\Administrator\diag\tnslsnr\LS--20171012URU\listener\trace\listener.log删除listener.log文件即可。......
  • 交通运输(Wormhole Transportaion) 题解
    传送门交通运输(WormholeTransportaion)题目大意有\(n\)个点和\(m\)个点对,你需要构造一张\(m-1\)条边的无向图,使得\(m\)个点对间最短路之和最小。求最小值及取到最小值的方案数。\(2\len\le2000,2\lenm\le2\times10^7,1\leu_i,v_i\len,u_i\neqv_i\)。......
  • P3919 【模板】可持久化线段树 1(可持久化数组) 题解
    一、题目描述:维护这样的一个长度为$n$的数组,支持以下两种操作$1$:在某个历史版本上修改某一个位置上的值$2$:访问某个历史版本上的某一位置的值每进行一次操作,就会生成一个新的版本(对于操作2,生成的就是一个完全一样的版本)。版本编号即为当前操作......
  • 题解:独占访问2 Exclusive Access 2
    题目链接怎么唯一一篇题解这么抽象,完全看不懂给定一张无向图,求给这张图定向成DAG之后的最长路最短是多少。转化一下变成对DAG进行分层,每一层之间的点没有连边,使得层数尽可能少,那么最后的层数就是答案。那么就求出若干个独立集,让独立集总数尽可能少。这是经典的色数问题,我们......
  • GYM102392 简要题解
    自己下午闲着没事单挑了一下,两小时左右一度rk1,但后继无力了。。。。A.MaxorMin肯定沿着出现过的数操作;然后发现如果a[i]=k,a[j]>k,a[k]<k就会增加一次操作所以维护一下差分序列即可。B.LevelUp两维DP,这个疑似edu出过。要注意的是:需要关于x排个序,不然会漏一些转移。D.......