题目背景:考完试回来发现了一道原题QAQ

题目背景

John的农场缺水了!!!

题目描述

农民John 决定将水引入到他的n(1<=n<=300)个牧场。他准备通过挖若

干井,并在各块田中修筑水道来连通各块田地以供水。在第i 号田中挖一口井需要花费W_i(1<=W_i<=100,000)元。连接i 号田与j 号田需要P_ij (1 <= P i , j P_{i,j} Pi,j <= 100,000 , P j , i P_{j,i} Pj,i= P i , j P_{i,j} Pi,j)元。

请求出农民John 需要为使所有农场都与有水的农场相连或拥有水井所需要的钱数。

输入输出格式

输入格式:

第1 行为一个整数n。

第2 到n+1 行每行一个整数,从上到下分别为W_1 到W_n。

第n+2 到2n+1 行为一个矩阵,表示需要的经费(P_ij)。

输出格式:

只有一行,为一个整数,表示所需要的钱数。

输入输出样例

输入样例#1:

4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0

输出样例#1:

9

说明

John等着用水,你只有1s时间!!!


做法:另类的最小生成树啊就是!
为什么在考场上没想出来??

只要设立一个虚点用来存点权就好了!!


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std ;
int read(){ //快读
	int x = 0 ;int f = 1 ; char s= getchar() ;
	while(s>'9'||s<'0') {if(s=='-')f=-1;s=getchar();}
	while(s<='9'&&s>='0') {x=x*10+(s-'0');s=getchar();}
	return x*f ;
}
int n ;
int w[500] ;
struct dy{//结构体
	int x , y , z ;
}a[200010];int t ;
void add(int x , int y,int z) {
	a[++t].x = x ;
	a[t].y = y ;
	a[t].z = z ;
}int vis[500][500] ;
int fa[500] ;
int find(int x) {
	if(fa[x] != x ) fa[x] = find(fa[x]) ;
	return fa[x] ; 
}
void unionn(int x , int y ) {
	x = find(x) ;
	y = find(y) ;
	fa[x] = y ;
}
int cmp(dy x , dy y) {
	return x.z < y.z ;
}
int main(){
	n = read() ;
	for(int i = 1 ; i <= n ; i++) {
		w[i] = read() ;
		add(0,i,w[i]) ;//存放点权
	}
	for(int i = 1 ; i <= n ; i ++) {
		for(int j = 1 ; j <= n ; j ++) {
			int x ;
			x = read() ;
			if(i == j) continue ;//为了防止出现BUG,当有向图来存
			if(vis[i][j]) continue ;
			vis[i][j] = 1 ;
			add(i,j,x) ;
		}
	}
	int tot = 0, k = 0 ;
	sort(a+1,a+1+t,cmp) ;
	for(int i = 0 ; i <= n ; i ++) fa[i] = i ;
	for(int i = 1 ; i <= t ; i ++) {//kruskal 算法
		if(find(a[i].x) != find(a[i].y)) {
			unionn(a[i].x , a[i].y) ;
  			k ++ ;
			tot += a[i].z ;
		}
		if(k == n) break ;
 	} 
 	printf("%d\n",tot) ;
	return 0;
} 

完结散花!!!