例题一:剑鱼行动(Swordfish).
题目描述:给定平面上N个城市的坐标,计算连接这n个城市所需线路长度的最小值。
输出描述:如下图所示,每两个测试数据的输出之间输出一个空行
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<stdlib.h>
using namespace std;
#define MAXN 110
#define MAXM 5000
struct edge
{
int u,v;
double w;
}edges[MAXN];
int parent[MAXN];
int n,m;
double x[MAXN],y[MAXN];///每个顶点x坐标和y坐标
int i,j;
double sumweight;
void UFset()
{
for(i=0;i<n;i++)
parent[i]=-1;
}
int Find(int x)
{
int s;
for(s=x;parent[s]>=0;s=parent[s]);
while(s!=x)///压缩路径
{
int temp=parent[x];
parent[x]=s;
x=temp;
}
return s;
}
void Union(int R1,int R2)
{
int r1=Find(R1);
int r2=Find(R2);
int temp=parent[r1]+parent[r2];
if(parent[r1]>parent[r2])///加权法则
{
parent[r1]=r2;
parent[r2]=temp;
}
else
{
parent[r2]=r1;
parent[r1]=temp;
}
}
int cmp(const void *a,const void *b)
{
edge aa=*(const edge *)a;
edge bb=*(const edge *)b;
if(aa.w>bb.w) return 1;
else
return -1;
}
void Kruskal()
{
int num=0;
int u,v;
UFset();
for(i=0;i<m;i++)
{
u=edges[i].u;
v=edges[i].v;
if(Find(u)!=Find(v))
{
sumweight+=edges[i].w;
num++;
Union(u,v);
}
if(num>=n-1)
break;
}
}
int main()
{
double d;
int kase=1;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
for(i=0;i<n;i++)
scanf("%lf%lf",&x[i],&y[i]);
int mi=0;///记录边的数目
for(i=0;i<n;i++)///任意两个顶点间的距离,有意思
for(j=i+1;j<n;j++)
{
d=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
edges[mi].u=i;
edges[mi].v=j;
edges[mi].w=d;
mi++;
}
m=mi;
qsort(edges,m,sizeof(edges[0]),cmp);///快速排序
sumweight=0.0;
Kruskal();
if(kase>1)///第一组测试数据前有空格
{
printf("\n");
getchar();
}
printf("Case #%d:\n",kase);
printf("The minimum distance is: %0.2f\n",sumweight);
kase++;
}
return 0;
}
测试数据:
例题二:网络(Network)
先输入顶点和边,然后是每条边的起始点和边的权值
输出描述:首先输出最长的单根网线的长度。然后输出设计方案:先输入一个整数p,代表所使用的网线的数目,然后输出p对顶点,表示每对网线所连接的集线器的编号
#include<cstdio>
#include<iostream>
#include<cstring>
#include<stdlib.h>
using namespace std;
#define MAXN 1005
#define MAXM 15005
struct edge
{
int u,v,w;
}edges[MAXM];
int parent[MAXN];
int ans[MAXN],ai;///存储的是依次选择的边的序号;数组ans的下标
int n,m;
int num,maxedge;///最长的边
int i,j;
void UFset()
{
for(i=0;i<n;i++)
parent[i]=-1;
}
int find(int x)
{
int s=x;
for(s=x;parent[s]>=0;s=parent[s]);
while(s!=x)///压缩路径
{
int temp=parent[x];
parent[x]=s;
x=temp;
}
return s;
}
void Union(int R1,int R2)
{
int r1=find(R1);
int r2=find(R2);
int temp=parent[r1]+parent[r2];
if(parent[r1]>parent[r2])///加权法则
{
parent[r1]=r2;
parent[r2]=temp;
}
else
{
parent[r2]=r1;
parent[r1]=temp;
}
}
int cmp(const void *a,const void *b)
{
edge aa=*(const edge *)a;
edge bb=*(const edge *)b;
return aa.w-bb.w;
}
void Kruskal()
{
ai=0;
num=0;
maxedge=0;
int u,v;
UFset();
for(i=0;i<m;i++)
{
u=edges[i].u;
v=edges[i].v;
if(find(u)!=find(v))
{
ans[ai]=i;
ai++;
if(edges[i].w>maxedge)
maxedge=edges[i].w;
num++;
Union(u,v);
}
if(num>=n-1)
break;
}
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=0;i<m;i++)
scanf("%d%d%d",&edges[i].u,&edges[i].v,&edges[i].w);
qsort(edges,m,sizeof(edges[0]),cmp);
Kruskal();
printf("%d\n",maxedge);
printf("%d\n",num);
for(i=0;i<num;i++)///ans[]存储的是依次选择的边的序号
printf("%d %d\n",edges[ans[i]].u,edges[ans[i]].v);
}
return 0;
}