数据结构与算法实验题 7.2 连环计
问题描述:
赤壁之战前夕,庞统向周瑜献连环计,瑜设计使蒋干邀庞统到曹营。操与统同观营寨,又共论兵法。统对答如流使操敬服。统乘机提出:大江中风浪不息使北兵易生疾病。可将大
小船配搭,首尾用铁环连锁,铺阔板以便人马行走。操闻之大喜,派人连夜打造连环大钉,锁住船只。
每打造一单位长度的铁索要花费一单位的钱,曹操希望用最少的花费将 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; }
新 blog : www.hrwhisper.me