程序设计思维与实践 Week6 作业 C 掌握魔法の东东 I

题目描述:

东东在老家农村无聊,想种田。农田有 n 块,编号从 1~n。种田要灌氵
众所周知东东是一个魔法师,他可以消耗一定的 MP 在一块田上施展魔法,使得黄河之水天上来。他也可以消耗一定的 MP 在两块田的渠上建立传送门,使得这块田引用那块有水的田的水。 (1<=n<=3e2)
黄河之水天上来的消耗是 Wi,i 是农田编号 (1<=Wi<=1e5)
建立传送门的消耗是 Pij,i、j 是农田编号 (1<= Pij <=1e5, Pij = Pji, Pii =0)
东东为所有的田灌氵的最小消耗

input:

第1行:一个数n
第2行到第n+1行:数wi
第n+2行到第2n+1行:矩阵即pij矩阵

output:

东东最小消耗的MP值

思路:

如果没有“黄河之水天上来”的神奇操作,这个题会是一个最小生成树的模板题。

但不只是可以连接沟渠引水,同时也可以从“天上”获取水。总之,无论进行那种操作,都会付出一定的代价,而这种代价本质上没有任何区别,只要求最终的和最小即可。所以考虑加入第n+1个节点,对于第i块田地从“天上”引水的做法,看作是从第n+1块田地连接了沟渠,对于这n+1个节点求最小生成树即可。代码中使用的是Kruskal算法。

#include<iostream>
#include<algorithm>
using namespace std;
const int maxx=100010;
int n,w,tot,sum,ans,father[maxx];
struct node
{
	int u;
	int v;
	int w;
	bool operator <(const node&o)const
	{
		return w<o.w;
	}
}e[maxx];
int find(int x)
{
	if(x!=father[x])
	father[x]=find(father[x]);
	return father[x];
}
void unionn(int a,int b)
{
	int fa=find(a);
	int fb=find(b);
	father[fa]=fb;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>w;
		e[++tot].u=i;
		e[tot].v=n+1;
		e[tot].w=w;
	}
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	  {
	  	cin>>w;
	  	if(i!=j)
	  	{
	  		e[++tot].u=i;
		  	e[tot].v=j;
		  	e[tot].w=w;
		}
	  }
	for(int i=1;i<=n+1;i++)
	father[i]=i;
	sort(e+1,e+tot+1);
	for(int i=1;i<=tot;i++)
	{
		if(find(e[i].u)!=find(e[i].v))
		{
			unionn(e[i].u,e[i].v);
			ans+=e[i].w;
			sum++;
		}
		if(sum==n)
		break; 
	}
	cout<<ans;
	return 0;
}

 

发布了272 篇原创文章 · 获赞 222 · 访问量 16万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览