新的开始

前言

可恶啊我已经几个月没写博客了
刚才查徒步旅行时意外地翻到了某同校大佬的题解,感触挺深的,还是应该要总结啊
而且反正不去机房就多写几篇吧


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

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

在这一口矿井上建立一个发电站,费用为 (发电站的输出功率可以供给任意多个矿井)。
将这口矿井与另外的已经有电力供应的矿井之间建立电网,费用为 。
小 FF 希望身为「NewBe_One」计划首席工程师的你帮他想出一个保证所有矿井电力供应的最小花费。

输入格式
第一行一个整数 ,表示矿井总数。

第 行,每行一个整数,第 个数 表示在第 口矿井上建立发电站的费用。

接下来为一个 的矩阵 ,其中 表示在第 口矿井和第 口矿井之间建立电网的费用(数据保证有,且 )。

输出格式
输出仅一个整数,表示让所有矿井获得充足电能的最小花费。

样例
样例输入
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
样例输出
9
样例解释
小 FF 可以选择在4号矿井建立发电站然后把所有矿井都不其建立电网,总花费是 9


看到题时觉得很奇怪,虽然想到了最小生成树,但是多出了发电站这个东西,肯定不可能去枚举发电站的位置.
所以可以建造一个不存在的"矿井",编号就为n+1,然后把它和每条边都连起来,边权就是在那个矿井建发电站的花费

但是如何保证至少会有一个发电站呢?
回过头来看最小生成树的定义,发现最小生成树会把所有点连上,而其他矿井最初都没有与n+1号矿井的边,想要连接,只能通过n+1到他们的边到达,花费也就是发电站的价格,就没有问题了
超级源点的思想本来暑假讲过,但我一直没去找题做

code:

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int n,G[305][305],a[305],dis[305],ans;
bool vis[305];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		G[n+1][i]=a[i];
	}
	n+=1;
	for(int i=1;i<=n-1;i++)
	{
		for(int j=1;j<=n-1;j++)
		{
			scanf("%d",&G[i][j]);
		}
		G[i][i]=0x3f3f3f3f;
	}
	vis[n]=1;
	G[n][n]=0;
	for(int i=1;i<=n-1;i++)
	{
		dis[i]=G[n][i];
	}
	vis[n]=1;
	int x;
	for(int i=1;i<=n-1;i++)//用prim求出最小生成树
	{
		x=-1;
		for(int j=1;j<=n-1;j++)
		{
			if(!vis[j]&&(x==-1||dis[j]<dis[x]))
			{
				x=j;
			}
		}
		ans+=dis[x];
		vis[x]=1;
		for(int j=1;j<=n-1;j++)
		{
			dis[j]=min(dis[j],G[x][j]);
		}
	}
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值