本文搬运自本人初中博客园博客,若图片加载不出来,可到原文查看:https://www.cnblogs.com/zhangtingxi/p/16267581.html
题目
发展采矿业当然首先得有矿井,小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 n n n 口矿井,但他似乎忘记考虑的矿井供电问题……
为了保证电力的供应,小 FF 想到了两种办法:
在这一口矿井上建立一个发电站,费用为 v v v (发电站的输出功率可以供给任意多个矿井)。
将这口矿井与另外的已经有电力供应的矿井之间建立电网,费用为 p p p 。
小 FF 希望身为「NewBe_One」计划首席工程师的你帮他想出一个保证所有矿井电力供应的最小花费。
思路
设 a i a_i a i 代表当前此点的最小代价 ,则开始 有 a i = v i a_i=v_i a i = v i 。
然后我们进行 n n n 次来逐个点确定 其代价,假设第 j j j 次确立的点为 k k k ,需满足 k k k 之前未确立 且是剩余点中 a k a_k a k 最小 。
然后对于此时答案 a n s ans an s ,我们让其加上 a k a_k a k ,之后对所有未确定 的 a a a 进行更新,例如对于剩余的某个点 i i i ,有 a i = min ( a i , p k , i ) a_i=\min(a_i,\; p_{k,i}) a i = min ( a i , p k , i ) 。
上述过程均可暴力 实现,复杂度为 O ( n 2 ) O(n^2) O ( n 2 ) 。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <bits/stdc++.h> using namespace std;#define int long long inline int read () {int x=0 ,f=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )f=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+ (x<<3 )+(ch^48 );ch=getchar ();}return x*f;} #define N 310 int n, m, i, j, k; int v[N], b[N], a[N], p[N][N], ans; signed main () { n=read (); a[k=0 ]=1e9 ; for (i=1 ; i<=n; ++i) v[i]=a[i]=read (); for (i=1 ; i<=n; ++i) for (j=1 ; j<=n; ++j) p[i][j]=read (); for (i=1 ; i<=n; ++i) { for (j=1 , k=0 ; j<=n; ++j) if (!b[j] && a[j]<a[k]) k=j; for (j=b[k]=1 , ans+=a[k]; j<=n; ++j) if (!b[j]) a[j]=min (a[j], p[k][j]); } printf ("%lld" , ans); return 0 ; }
总结
此类题目算是思维题 ,对于每个位置代价不确定 时,可以考虑逐个确定。
可以考虑贪心 思想,有点类似Dij 或Prim ,先对代价最小 的点进行处理,然后更新其他点,再继续进行处理。
有些题目可能要加上堆优化 。