首先,我freopen已经潜水了很久了,今天我就要走上陆地,完成小蝌蚪找妈妈,啊呸,是由两栖动物进化为哺乳动物的壮举。
其次,我现在正在学习图论,什么弗雷伊德啊,迪杰斯特拉啊,欧拉回路以后会补的,今天我来讲一讲最小生成树。
最小生成树是指在有n个顶点的图中,选n-1条边,使其成为一棵树,并使边的长度和相等,具体可以查度娘,找最小生成树可以用prim算法,或是kruskal算法。这些同样以后会讲,今天我用kruskal解决了这样一题:
【USACO09 OCT】灌溉牧场
时间限制: 1 Sec 内存限制: 64 MB
提交: 43 解决: 8
[提交][状态][讨论版]
题目描述
Farmer John 决定把水引到N个牧场 N (1 <= N <= 300),牧场正好从1..N编号。FJ可以用两种方法来引水:
(1)在牧场上挖一口水井;
(2)从其它已经有水的牧场连一根水管。
在牧场i挖水井的费用为W_i (1 <= W_i <= 100,000),在牧场i和j之间连水管的费用为P_ij (1 <= P_ij <=100,000; P_ij = P_ji; P_ii=0)
请算出FJ把水引到所有牧场的最小费用。
输入
第1行: 1个整数 N
第2..N + 1行: 只有1个整数 W_i
第N+2..2N+1行:每有 N 个空格分开的整数,第j个表示 P_ij
输出
第1行: 1个整数表示引水到所有牧场的最小费用。
样例输入
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
样例输出
9
提示
样例说明: 一共有4个牧场。挖水井的代价分别为5,4,4,3. 在不同牧场之间连水管的代价分别是 2, 3, 和 4 。Farmer John 在第4个牧场挖一口井,然后分别从第4个牧场连到其它牧场,代价为: 3 + 2 + 2 + 2 = 9.
这题让我想到了山区建小学,但这题更像图论中的最小生成树问题,可水井是十分棘手的,我第一个想法是用kruskal,多加两层循环,让他变成将一个图分解为多个最小生成树,每个树都要有额外的花费,即水井费用。
但是这显然不行,因为这太烦了,我尝试都没尝试就放弃了,如果你们有兴趣的话就尝试一下吧,如果成功了,就把这个算法命名为Freopen-XXX算法吧。
这道题的真正解法还是最小生成树,来做个猜想:水井的水从哪来呢?从地下,那我们就可以把地下认为是第0个牧场,而这个牧场是有水的。而打水井的钱就是与这第0个牧场连水管的价格,然后就做这0~n个牧场的最小生成树。
而最小生成树的代码就问度娘啦:
代码RT:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
struct edge{
int x,y,v,b;
bool operator < (const edge& a)const{
return v<a.v;
}
}e[99999];
int f[302],m,n,x,y,v,sum,g;
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&v);
e[m].v=v;
e[m].x=i;
e[m++].y=n+1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
scanf("%d",&v);
if(i==j) continue;
e[m].v=v;
e[m].x=i;
e[m++].y=j;
}
for(int i=1;i<=n;i++)f[i]=i;
sort(e+0,e+m);
for(int i=0;i<m;i++){
int a=find(e[i].x),b=find(e[i].y);
if(a!=b)
{
f[a]=b;
sum+=e[i].v;
}
}
printf("%d",sum);
}
这里把第0个牧场写成第n+1个牧场,符合我的风格,庆祝了我停止潜水的壮举,拜拜。