【一本通 1488:新的开始】题解
题目链接
题目
发展采矿业当然首先得有矿井,小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 \(n\) 口矿井,但他似乎忘记考虑的矿井供电问题……
为了保证电力的供应,小 FF 想到了两种办法:
在这一口矿井上建立一个发电站,费用为 \(v\)(发电站的输出功率可以供给任意多个矿井)。
将这口矿井与另外的已经有电力供应的矿井之间建立电网,费用为 \(p\)。
小 FF 希望身为「NewBe_One」计划首席工程师的你帮他想出一个保证所有矿井电力供应的最小花费。
思路
设 \(a_i\) 代表当前此点的最小代价,则开始有 \(a_i=v_i\)。
然后我们进行 \(n\) 次来逐个点确定其代价,假设第 \(j\) 次确立的点为 \(k\),需满足 \(k\) 之前未确立且是剩余点中 \(a_k\) 最小。
然后对于此时答案 \(ans\),我们让其加上 \(a_k\),之后对所有未确定的 \(a\) 进行更新,例如对于剩余的某个点 \(i\),有 \(a_i=\min(a_i,\; p_{k,i})\)。
上述过程均可暴力实现,复杂度为 \(O(n^2)\)。
代码
#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 mo
#define N 310
//#define M
int n, m, i, j, k;
int v[N], b[N], a[N], p[N][N], ans;
signed main()
{
// freopen("tiaoshi.in","r",stdin);
// freopen("tiaoshi.out","w",stdout);
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,先对代价最小的点进行处理,然后更新其他点,再继续进行处理。
有些题目可能要加上堆优化。
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/16267581.html