20190708新的开始

题目描述
发展采矿业当然首先得有矿井,小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 n 口矿井,但他似乎忘记考虑的矿井供电问题……
为了保证电力的供应,小 FF 想到了两种办法:
在这一口矿井上建立一个发电站,费用为 v(发电站的输出功率可以供给任意多个矿井)。
将这口矿井与另外的已经有电力供应的矿井之间建立电网,费用为 p。
小 FF 希望身为「NewBe_One」计划首席工程师的你帮他想出一个保证所有矿井电力供应的最小花费。
输入
第一行一个整数 n,表示矿井总数。
第 2∼n+1 行,每行一个整数,第 i 个数 vi表示在第 i 口矿井上建立发电站的费用。
接下来为一个 n×n的矩阵 p,其中 p(i,j)表示在第 i口矿井和第 j 口矿井之间建立电网的费用(数据保证有p_{i,j}=p_{j,i},且 p_{i,i}=0。
输出
输出仅一个整数,表示让所有矿井获得充足电能的最小花费。
样例输入
4  
5  
4 
4  
3  
0 2 2 2  
2 0 3 3  
2 3 0 4  
2 3 4 0
样例输出
9
提示
【样例解释】
小 FF 可以选择在 4 号矿井建立发电站然后把所有矿井都不其建立电网,总花费是 3+2+2+2=9。
【数据范围】
对于 30%的数据:1≤n≤50;
对于 100% 的数据:1≤n≤300,0≤vi,p(i,j)≤10^5。
 
#include<bits/stdc++.h>
#define INF 214748364
using namespace std;
int v[305],p[305][305];
int mins[305];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>v[i],p[n+1][i]=p[i][n+1]=v[i];//虚拟节点
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++) cin>>p[i][j];
	}//以下为Prim最小生成树
    for(int i=1;i<=n+1;i++) mins[i]=p[n][i];
    mins[n]=0;
	int ans=0,k;
    for(int i=1;i<=n;i++)
	{
        int minn=INF;
        for(int j=1;j<=n+1;j++)
		{
            if(mins[j]>0&&mins[j]<minn) minn=mins[j],k=j;
        }
        mins[k]=0,ans+=minn;
        for(int j=1;j<=n+1;j++) mins[j]=min(mins[j],p[k][j]);
    }
    cout<<ans;
    return 0;
}

  本题显然需要最小生成树解决(最小生成树之变式),但并不是单纯的最小生成树,因为涉及到了“发电站”的概念。为了处理这个问题,我们需要增加一个节点,让这些节点与每个矿井连通,权值为在该矿井上修建发电站的费用。然后在新图上求最小生成树即可。

原文地址:https://www.cnblogs.com/dong-ji-yuan/p/11150895.html