EOJ2067 最小生成树 prime算法和kruskal算法实现
题目:
Building Roads |
Time Limit:1000MS Memory Limit:30000KB
Total Submit:476 Accepted:144
Description
Farmer John had just acquired several new farms! He wants to connect the farmswith roads so that he can travel from any farm to any other farm via a sequenceof roads; roads already connect some of the farms.
Each of the N (1 <= N <= 1,000) farms (conveniently numbered 1..N) isrepresented by a position (X_i, Y_i) on the plane (0 <= X_i <=1,000,000;0 <= Y_i <= 1,000,000). Given the preexisting M roads(1 <= M <=1,000) as pairs of connected farms, help Farmer John
determine the smallest length of additional roads he must build to connect allhis farms.
Input
* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Two space-separated integers: X_i and Y_i
* Lines N+2..N+M+2: Two space-separated integers: i and j, indicating thatthere is already a road connecting the farm i and farm j.
Output
4 1
1 1
3 1
2 3
4 3
1 4
INPUT DETAILS:
Four farms at locations (1,1), (3,1), (2,3), and (4,3). Farms 1 and 4 areconnected by a road.
Sample Input
* Line 1: Smallest length of additional roads required to connect allfarms,printed without rounding to two decimal places. Be sure to calculate distancesas 64-bit floating point numbers.
Sample Output
4.00
OUTPUT DETAILS:
Connect farms 1 and 2 with a road that is 2.00 units long, then connect farms 3and 4 with a road that is 2.00 units long. This is the best we can do, andgives us a total of 4.00 unit lengths.
题目分析:
给定一些点的坐标,要在这些点间修路,一些点间的路已经修好,求最短的修路长度,使得图连通,最小生成树练习题。先预处理出所有点间的距离,然后把已经修好的点间的距离改成0。接下来可用prime算法和kruskal算法实现。1.prime算法思路类似dijkstra算法,每次选择到正在构建的生成树距离最短的点加入树的构建中,并通过新加入的点更新此集合与集合外各点的最小距离。2.kruskal算法每次取最短边来建树,且不能出现回路。
比较两个算法发现prime算法效率较高,因为当图接近完全图时,kruskal的复杂图比prime算法多了一个log(n*n)的常数。
两种实现代码如下:
1. prime算法:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
struct Node{
double x,y;
}node[1005];
double cost[1005][1005];
double low[1005];
bool vis[1005];
double dis(Node a,Node b){
returnsqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double prime(int n){
int i,j,k;
double ans=0.0;
vis[1]=true;
for(i=2;i<=n;++i)
low[i]=cost[1][i];
for(i=1;i<=n-1;++i){
double minn=1000000000;
for(j=1;j<=n;++j){
if(!vis[j] &&minn>low[j]){
minn=low[j];k=j;
}
}
vis[k]=true;
ans+=low[k];
for(j=1;j<=n;++j){
if(!vis[j]){
low[j]=min(low[j],cost[k][j]);
}
}
}
return ans;
}
int main()
{
int n,m,i,j;
memset(vis,false,sizeof(vis));
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
scanf("%lf%lf",&node[i].x,&node[i].y);
for(i=1;i<=n;++i){
for(j=i+1;j<=n;++j){
cost[j][i]=cost[i][j]=dis(node[i],node[j]);
}
}
for(i=0;i<m;++i)
{
int x,y;
scanf("%d%d",&x,&y);
cost[x][y]=cost[y][x]=0.0;
}
double ans=prime(n);
printf("%.2f\n",ans);
return 0;
}
2. kruscal算法:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
struct Node{
double x,y;
}node[1005];
struct E{
int pt1,pt2;
double length;
}e[1005*1005/2];
int set[1005];
int find(int x){
returnx==set[x]?x:(set[x]=find(set[x]));
}
double dis(Node a,Node b){
return(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(const E& a,const E& b){
return a.length<b.length;
}
double kruskal(int n,int k){
double ans=0.0;
int cnt=0,i;
for(i=0;i<k;++i){
intfx=find(e[i].pt1),fy=find(e[i].pt2);
if(fx==fy) continue;
set[fx]=fy;
ans+=sqrt(e[i].length);
++cnt;
if(cnt==n-1) break;
}
return ans;
}
int main()
{
int n,m,i,j,k=0;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
scanf("%lf%lf",&node[i].x,&node[i].y);
for(i=1;i<=n;++i){
for(j=1;j<=i-1;++j){
e[k].pt1=i;
e[k].pt2=j;
e[k++].length=dis(node[i],node[j]);
}
}
for(i=0;i<m;++i)
{
int x,y;
scanf("%d%d",&x,&y);
if(x<y) swap(x,y);
// cout<<(x-2)*(x-1)/2+y-1<<endl;
e[(x-2)*(x-1)/2+y-1].length=0.0;
}
sort(e,e+k,cmp);
for(i=1;i<1005;++i)set[i]=i;
double ans=kruskal(n,k);
printf("%.2f\n",ans);
return 0;
}
原文地址:http://blog.csdn.net/fangpinlei/article/details/41806991