问题描述:
赤壁之战前夕,庞统向周瑜献连环计,瑜设计使蒋干邀庞统到曹营。操与统同观营寨,又共论兵法。统对答如流使操敬服。统乘机提出:大江中风浪不息使北兵易生疾病。可将大
小船配搭,首尾用铁环连锁,铺阔板以便人马行走。操闻之大喜,派人连夜打造连环大钉,锁住船只。
每打造一单位长度的铁索要花费一单位的钱,曹操希望用最少的花费将 n 艘战船连接起来(任意两艘战船直接或间接被铁索连接),每艘战船可以看成一个点,坐标为(xi,yi),曹营中有一位神秘人物,他所在的战船必须和曹操所在战船直接连接,求最小花费。
数据输入:
第一行战船数 n(2<=n<=100)。
kruskal
赤壁之战前夕,庞统向周瑜献连环计,瑜设计使蒋干邀庞统到曹营。操与统同观营寨,又共论兵法。统对答如流使操敬服。统乘机提出:大江中风浪不息使北兵易生疾病。可将大
小船配搭,首尾用铁环连锁,铺阔板以便人马行走。操闻之大喜,派人连夜打造连环大钉,锁住船只。
每打造一单位长度的铁索要花费一单位的钱,曹操希望用最少的花费将 n 艘战船连接起来(任意两艘战船直接或间接被铁索连接),每艘战船可以看成一个点,坐标为(xi,yi),曹营中有一位神秘人物,他所在的战船必须和曹操所在战船直接连接,求最小花费。
数据输入:
第一行战船数 n(2<=n<=100)。
第二行神秘人物所在的战船序号 a,曹操所在战船序号 b,(1<=a,b<=n,a!=b),战船序号从 1 到 n。
接下来 n 行,每行两个实数(建议定义成 double 类型):xi,yi(-1000<=xi,yi<=1000),表
示序号为 i 的战船的坐标。
结果输出:
连接 n 艘战船的最小花费,输出答案的时候四舍五入保留两位小数。
输入示例:
4
2 3
0 0
1 0
0 -1
1 -1
输出示例:
3.14
MST最小生成树的变形。。敢不敢不要那么明显。。。
要求某辆船和曹操的船相连接,MST多一步就可以了(卖个关子,很明显的)
-----------------2013/12/17上传-----------------
prim
#include<cstdio>
#include<cmath>
const int MAXN=101;
const int INF=9999999;
double map[MAXN][MAXN];
double dis[MAXN];
struct point
{
double x,y;
}ship[MAXN];
void prim(int a,int b,int n)
{
int i,j;
for(i=1;i<=n;i++)
dis[i]=INF;
bool vis[MAXN]={0};
int cur=a;
vis[a]=1;
dis[a]=0;
for(i=1;i<=n;i++) //prim算法的做法是先从a开始扩散,更新与a连接的所有船。
{ //只不过把下一步找出最小的边改为直接从b开始
if(!vis[i] )
dis[i]=map[cur][i];
}
cur=b;
vis[b]=1;
for(i=1;i<=n;i++)
{
double mini=INF;
for(j=1;j<=n;j++)
if(!vis[j] && dis[j] > map[cur][j])
dis[j]=map[cur][j];
for(j=1;j<=n;j++)
if(!vis[j] && mini > dis[j])
mini=dis[cur=j];
vis[cur]=true;
}
}
int main()
{
int n,a,b;
scanf("%d",&n);
scanf("%d%d",&a,&b);
int i,j;
for(i=1;i<=n;i++)
scanf("%lf%lf",&ship[i].x,&ship[i].y);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
map[i][j]= map[j][i] =
sqrt((ship[j].y -ship[i].y) *(ship[j].y -ship[i].y) + (ship[j].x -ship[i].x)*(ship[j].x -ship[i].x));
}
}
prim(a,b,n);
double ans=0;
for(i=1;i<=n;i++)
ans+=dis[i];
printf("%.2lf\n",ans);
return 0;
}
kruskal
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=102;
const int INF=9999999;
int fa[MAXN];
struct point
{
double x,y;
}ship[MAXN];
struct dot
{
int x,y;
double dis;
}dis[MAXN*MAXN];
int find(int cur)
{
return fa[cur]==cur?cur:fa[cur]=find(fa[cur]);
}
bool operator < (const dot &a,const dot& b)
{
return a.dis<b.dis;
}
int main()
{
int n;
scanf("%d",&n);
int a,b;
scanf("%d%d",&a,&b);
int i,j;
for(i=1;i<=n;i++)
scanf("%lf%lf",&ship[i].x,&ship[i].y);
double ans;
int len=0;
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
dis[len].x=i;
dis[len].y=j;
dis[len].dis=sqrt((ship[j].y -ship[i].y) *(ship[j].y -ship[i].y) + (ship[j].x -ship[i].x)*(ship[j].x -ship[i].x));
if(i==a && j==b || i==b && j==a)
ans=dis[len].dis;
len++;
}
}
for(i=1;i<=n;i++)
fa[i]=i;
sort(dis,dis+len);
fa[b]=a; //kruakal 做法更简单,直接一开始把a和b设为一个集合就可以了
//然后把答案加上a到b边的值就可以了。
for(i=0;i<len;i++)
{
int rootx=find(dis[i].x);
int rooty=find(dis[i].y);
if(rootx!=rooty)
{
ans+=dis[i].dis;
fa[rootx]=rooty;
}
}
printf("%.2lf\n",ans);
return 0;
}