您的位置:首页 > 其它

图论之Watering Hole

2017-12-09 20:44 190 查看
题目描述

Farmer John希望把水源引入他的N (1 <= N <= 300) 个牧场,牧场的编号是1~N.他将水源引入某个牧场的方法有两个,一个是在牧场中打一口井,另一个是将这个牧场与另一个已经有水源的牧场用一根管道相连.

在牧场i中打井的费用是W_i (1 <= W_i <= 100000).

把牧场i和j用一根管道相连的费用是P_ij (1 <= P_ij <= 100000, P_ij = P_ji, P_ii = 0). 请你求出Farmer John最少要花多少钱才能够让他的所有牧场都有水源.

输入格式

第1行: 一个正整数N.

第2~N+1行: 第i+1行包含一个正整数W_i.

第N+2~2N+1行: 第N+1+i行包含N个用空格分隔的正整数,第j个数表示P_ij.

输出格式

总共有四个牧场.在1号牧场打一口井需要5的费用,在2或者3号牧场打井需要4的费用,在4号牧场打井需要3的费用.在不同的牧场间建立管道需要2,3或4的费用.

分析

唔。。。

其实这题就像它的题目一样,挺水的。。。

重点是做题的思路:

由于每个牧场都有自己的权值的道路的权值,所以可以在建图的时候,引入第n+1个点,标记为与1-n每个点都联通,权值为1-n个点自身的权值,然后可以对这n+1个点做prim求最小生成树;

或者可以在dis数组中将每个点的初值赋为该点的权值,然后再prim,同样可以达到题目的目的。

代码实现

include<bits/stdc++.h>

using namespace std;

int a[350][350];

int dis[350];

int vis[350];

int n;

int w,x,y;

int summ=0;

void prim(int s)//裸的prim

{

memset(dis,10,sizeof(dis));//如果用第二种方法,则需要在memset后给dis数组赋值

memset(vis,0,sizeof(vis));

for (int i=1;i<=n;i++)

dis[i]=a[s][i];

vis[s]=1;

for (int i=2;i<=n;i++)

{

int minn=100000000;

int c=0;

for (int j=1;j<=n;j++)

if (!vis[j] && dis[j]<minn)

{

minn=dis[j];

c=j;

}

vis[c]=1;

summ+=minn;

for (int j=1;j<=n;j++)

{

if (!vis[j] && a[c][j]<dis[j])

dis[j]=a[c][j];

}

}

}

int main()

{

cin >>n;

memset(a,10,sizeof(a));

for (int i=1;i<=n;i++)

{

cin >>w;

a[n+1][i]=w;

}//第n+1个点的构建

for (int i=1;i<=n;i++)

{

for (int j=1;j<=n;j++)

cin >>a[i][j];

}//读入邻接矩阵

n=n+1;

for (int i=1;i<=n;i++)

a

=0;//每个点到其自身的权值为0

prim(n);//这里一定要从新构建的点开始做prim,但是我也不知道为什么。。。

cout <<summ <<endl;

return 0;

}


总结

题目确实很水。。。但是核心部分就需要灵光一现的脑子了。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: