p1221网络布线(最小生成树 Prim(普里母)算法) p1222 Watering Hole
描述 Description
农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了用最小的消费,他想铺设最短的光纤去连接所有的农场。你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。每两个农场间的距离不会超过100000
输入格式 Input Format
第一行: 农场的个数,N(3<=N<=100)。
第二行..结尾: 后来的行包含了一个N*N的矩阵,表示每个农场之间的距离。当然,对角线将会是0,因为不会有线路从第i个农场到它本身。
输出格式 Output Format
只有一个输出,其中包含连接到每个农场的光纤的最小长度。
样例输入 Sample Input
4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
样例输出 Sample Output
28
这道题直接从第一个点开始作为光纤的起点链接每一个牧场,然后记录在哪个牧场时所用光纤最短。
然后使用prim算法,现将第一个牧场添加进入到图中,然后枚举每条边,寻找现在能到达的边中的最短的那条。
代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<iomanip> using namespace std; int a[1100][1100]; int dis[11000]; bool vis[11000]; int main() { int n; cin>>n; memset(a,10,sizeof(a)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cin>>a[i][j]; } } int minn1=100000,sum,sumn; for(int k=1;k<=n;k++) { memset(dis,10,sizeof(dis)); for(int i=1;i<=n;i++) dis[i]=a[k][i]; memset(vis,0,sizeof(vis)); vis[k]=1; sumn=0;sum=0; for(int i=2;i<=n;i++) { int minn=a[0][0],c=0; for(int j=1;j<=n;j++) if((!vis[j])&&(dis[j]<minn)) { minn=dis[j]; c=j; } vis[c]=1; sumn+=minn; for(int j=1;j<=n;j++) { if((a[c][j])<dis[j]&&(!vis[j])) dis[j]=a[c][j]; } } for(int j=1;j<=n;j++) { sum+=dis[j]; } if(sum<minn1) { minn1=sum; } } cout<<sum<<endl; return 0; }
其实sumn这个变量记录的就是从起始点牧场到达各个牧场的最短距离,枚举完后sumn=sum的。
Watering Hole
题目:
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最少要花多少钱才能够让他的所有牧场都有水源.
输入格式 Input Format
* 第1行: 一个正整数N.
* 第2~N+1行: 第i+1行包含一个正整数W_i.
* 第N+2~2N+1行: 第N+1+i行包含N个用空格分隔的正整数,第j个数表示P_ij.
输出格式 Output Format
总共有四个牧场.在1号牧场打一口井需要5的费用,在2或者3号牧场打井需要4的费用,在4号牧场打井需要3的费用.在不同的牧场间建立管道需要2,3或4的费用.
样例输入 Sample Input
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
样例输出 Sample Output
9
输出数据解释 Farmer John需要在4号牧场打一口井,然后把所有牧场都用管道连到1号牧场上,总共的花费是3+2+2+2=9.
时间限制 Time Limitation 1s
这道题直接直接从打井花费最少的地方开始打井,然后让用管子讲打井的牧场和其他牧场连通,比如:你在i花费3打了一口井要连到j牧场,连到j牧场要花费6,而在j牧场打一口井只用花费4,那就用在j牧场打井代替连接i到j,这样才会使花费最少.最后还是用Prim算法进行求最少花费。
代码如下:
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> using namespace std; int a[310][310]; int dis[1100]; bool vis[1100]; int sumn; int main() { //freopen("add.in","r",stdin); //freopen("add.out","w",stdout); memset(vis,false,sizeof(vis)); memset(dis,10,sizeof(dis)); int n; memset(a,10,sizeof(a)); cin>>n; int minn1=100000,s; for(int i=1;i<=n;i++) { cin>>dis[i]; if(dis[i]<minn1) { minn1=dis[i]; s=i; } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cin>>a[i][j]; } } sumn=0; sumn+=dis[s]; for(int i=1;i<=n;i++) { if(dis[i]>a[s][i]) dis[i]=a[s][i]; } vis[s]=1; for(int i=2;i<=n;i++) { int minn=9999999,c=0; for(int j=1;j<=n;j++) if((!vis[j])&&(dis[j]<minn)) { minn=dis[j]; c=j; } vis[c]=1; sumn+=minn; for(int j=1;j<=n;j++) { if((a[c][j]<dis[j])&&(!vis[j])) { dis[j]=a[c][j]; } } } cout<<sumn<<endl; return 0; }