当前位置: 代码迷 >> 综合 >> 【loj】#10066. 「一本通 3.1 练习 1」新的开始 (最小生成树·Prim)
  详细解决方案

【loj】#10066. 「一本通 3.1 练习 1」新的开始 (最小生成树·Prim)

热度:22   发布时间:2023-12-26 09:50:34.0

题目描述:

发展采矿业当然首先得有矿井,小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 nnn 口矿井,但他似乎忘记考虑的矿井供电问题……

为了保证电力的供应,小 FF 想到了两种办法:

  1. 在这一口矿井上建立一个发电站,费用为 v(发电站的输出功率可以供给任意多个矿井)。
  2. 将这口矿井与另外的已经有电力供应的矿井之间建立电网,费用为 p。

小 FF 希望身为「NewBe_One」计划首席工程师的你帮他想出一个保证所有矿井电力供应的最小花费。

题目链接:https://loj.ac/problem/10066

【分析】一开始想复杂了,在想应该不单单是求最小生成树,因为每个点还有权值,如果是点与边的组合.... 然而,想太多。只要把d数组初始赋值为每个点的权值而不是后来通过初始节点更新,就可以了。因为不管怎样后来还是要对d数组进行更新,那么比较点的权值和边权来决定是加点还是加边就好。emmm我是这么理解的,不知道对不对。

然后就是,求最小生成树了。n的范围只有300,Prim,然后邻接矩阵。其他,好像没啥要注意的了。

【代码】

#include<bits/stdc++.h>
using namespace std;const int maxn=300;
const int inf=0x3f3f3f3f;int vis[maxn];
int e[maxn][maxn];
int d[maxn];
int n,ans;void read()
{scanf("%d",&n);for(int i=0;i<n;i++)scanf("%d",&d[i]);for(int i=0;i<n;i++)for(int j=0;j<n;j++)scanf("%d",&e[i][j]);
}
void Prim(int x)
{memset(vis,0,sizeof(vis));int minn,k;ans=0;for(int i=0;i<n;i++){minn=inf;for(int j=0;j<n;j++){if(!vis[j] && minn>d[j])minn=d[j],k=j;}vis[k]=1;ans+=d[k];for(int j=0;j<n;j++){if(!vis[j] && d[j]>e[j][k])d[j]=e[j][k];}}
}
int main()
{ans=0;read();Prim(0);printf("%d\n",ans);return 0;
}