以(x,y)坐标的形式给出n个点,修建若干条路使得所有点连通(其中有两个给出的特殊点必须相邻),求所有路的总长度的最小值。

因对所修的路的形状没有限制,所以可看成带权无向完全图,边权值为两点间距离。因是稠密图,故用邻接矩阵存储更好(完全图,边数e达到n(n-1)/2)。

至此,可将问题抽象为求最小生成树的边权和。

用了prim+邻接矩阵,prim+邻接表+堆,kruscal各写了一遍,只是内存稍有差别

对于所给的特殊的两个相邻点,只需在开始循环前把这两个点加入子树集合并更新它们所到达的点的mincost即可。

 #include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std; const int MAX_N=;
const double INF=; struct Point
{
int x,y;
}a[MAX_N]; double dis(Point& p1, Point& p2)
{
return sqrt((double)(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
} int n;
int nike,apple;
double cost[MAX_N][MAX_N];//邻接矩阵(更适于稠密图)
double mincost[MAX_N];//集合到点i的最短距离
int used[MAX_N]; double prim()
{
double res;
for(int i=;i<n;i++)
{
mincost[i]=INF;
used[i]=;
}//将nike,apple两个点加入集合,并更新它们所到达的点的mincost
mincost[nike]=mincost[apple]=;
used[nike]=used[apple]=;
res=cost[nike][apple];
for(int i=;i<n;i++)
{
mincost[i]=min(mincost[i],cost[nike][i]);
}
for(int i=;i<n;i++)
{
mincost[i]=min(mincost[i],cost[i][apple]);
}
while()
{
int v=-;
for(int i=;i<n;i++)//找到集合以外的mincost最小的点
{
if(!used[i]&&(v==-||mincost[i]<mincost[v]))
v=i;
}
if(v==-) break;//不存在负权边
used[v]=;
res+=mincost[v];//加入集合,更新它所到达的点
for(int i=;i<n;i++)
{
mincost[i]=min(mincost[i],cost[i][v]);
}
}
return res;
} int main()
{
//freopen("1011.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
if(n==) break;
scanf("%d%d",&nike,&apple);
nike--;
apple--;
for(int i=;i<n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
for(int i=;i<n;i++)//求两点间距离,得到邻接矩阵
{
cost[i][i]=;
for(int j=i+;j<n;j++)
cost[i][j]=cost[j][i]=dis(a[i],a[j]);
}
printf("%.2lf\n",prim());
}
return ;
}

prim_邻接矩阵

 #include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
using namespace std; const int MAX_N=;
const double INF=; struct Point
{
int x,y;
}a[MAX_N]; double dis(Point& p1, Point& p2)
{
return sqrt((double)(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
} struct Edge
{
int to;
double cost;
Edge(){}
Edge(int tt,double cc):to(tt),cost(cc){}
};
typedef pair<double,int> P;//cost,to
int n;
int nike,apple;
double dis_na;
vector<Edge> G[MAX_N];
double mincost[MAX_N];//集合到点i的最短距离
int used[MAX_N]; double prim()
{
double res=;
for(int i=;i<n;i++)
{
mincost[i]=INF;
used[i]=;
}//将nike,apple两个点加入集合,并将与它们相邻的边推入队列
mincost[nike]=mincost[apple]=;
used[nike]=used[apple]=;
res=dis_na;
priority_queue<P,vector<P>,greater<P> >que;
for(int i=;i<G[nike].size();i++)
{
int u=G[nike][i].to;
if(used[u]||mincost[u]<G[nike][i].cost) continue;
mincost[u]=G[nike][i].cost;
que.push(P(mincost[u],u));
}
for(int i=;i<G[apple].size();i++)
{
int u=G[apple][i].to;
if(used[u]||mincost[u]<G[apple][i].cost) continue;
mincost[u]=G[apple][i].cost;
que.push(P(mincost[u],u));
}
while(!que.empty())
{
P p=que.top();
que.pop();
int v=p.second;
if(used[v]||mincost[v]<p.first) continue;
mincost[v]=p.first;
used[v]=;
res+=mincost[v];//加入集合,更新它所到达的点
for(int i=;i<G[v].size();i++)
{
int u=G[v][i].to;
if(!used[u]&&mincost[u]>G[v][i].cost)
{
mincost[u]=G[v][i].cost;
que.push(P(mincost[u],u));
}
}
}
return res;
} int main()
{
//freopen("4463.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
if(n==) break;
scanf("%d%d",&nike,&apple);
nike--;
apple--;
for(int i=;i<n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
for(int i=;i<n;i++) G[i].clear();
for(int i=;i<n;i++)//求两点间距离,得到表
{
for(int j=i+;j<n;j++)
{
double temp=dis(a[i],a[j]);
G[i].push_back(Edge(j,temp));
G[j].push_back(Edge(i,temp));
if(i==nike&&j==apple) dis_na=temp;
}
}
printf("%.2lf\n",prim());
}
return ;
}

prim_邻接表_堆

 #include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std; const int MAX_N=; int parent[MAX_N];
int rankk[MAX_N];
void init(int N)
{
for(int i=;i<=N;i++)
{
parent[i]=i;
rankk[i]=;
}
}
int find(int x)
{
if(x==parent[x]) return x;
return parent[x]=find(parent[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return ;
if(rankk[x]<rankk[y]) parent[x]=y;
else
{
parent[y]=x;
if(rankk[x]==rankk[y]) rankk[x]++;
}
}
bool same(int x,int y)
{
return find(x)==find(y);
} struct Point
{
int x,y;
}a[MAX_N]; double dis(Point& p1, Point& p2)
{
return sqrt((double)(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
} struct Edge
{
int from,to;
double cost;
}edges[MAX_N*MAX_N]; bool cmp(Edge e1,Edge e2)
{
return e1.cost<e2.cost;
} int n,m;
int nike,apple;
double dis_na; double kruscal()
{
double ans=;
init(n);
unite(nike,apple);
ans+=dis_na;
for(int i=;i<m;i++)
{
if(!same(edges[i].from,edges[i].to))
{
ans+=edges[i].cost;
unite(edges[i].from,edges[i].to);
}
}
return ans;
} int main()
{
//freopen("4463.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
if(n==) break;
scanf("%d%d",&nike,&apple);
nike--;
apple--;
for(int i=;i<n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
m=;
for(int i=;i<n;i++)//求两点间距离,得到所有边
{
for(int j=i+;j<n;j++)
{
double temp=dis(a[i],a[j]);
edges[m].from=i;
edges[m].to=j;
edges[m].cost=temp;
m++;
if((i==nike&&j==apple)||(i==apple&&j==nike)) dis_na=temp;
}
}
sort(edges,edges+m,cmp);
printf("%.2lf\n",kruscal());
}
return ;
}

kruscal_边数组

邻接矩阵版Prim算法求最小生成树,时间复杂度为O(n*n)。邻接表版prim用堆优化后理论上可达O(elogn),边数组版kruscal理论也为O(elogn),但此题是完全图,e=n(n-1)/2,故实为O(n*nlogn)>O(n*n)。--这段分析有待考证。。。

【HDU 4463 Outlets】最小生成树(prim,kruscal都可)的更多相关文章

  1. hdu 4463 Outlets(最小生成树)

    Outlets Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submi ...

  2. HDU—4463 Outlets 最小生成树

    In China, foreign brand commodities are often much more expensive than abroad. The main reason is th ...

  3. HDU 4463 Outlets 【最小生成树】

    <题目链接> 题目大意: 给你一些点的坐标,要求你将这些点全部连起来,但是必须要包含某一条特殊的边,问你连起这些点的总最短距离是多少. 解题分析: 因为一定要包含那条边,我们就记录下那条边 ...

  4. HDU 4463 Outlets(最小生成树给坐标)

    Problem Description In China, foreign brand commodities are often much more expensive than abroad. T ...

  5. hdu 4463 Outlets(最小生成树)

    题意:n个点修路,要求总长度最小,但是有两个点p.q必须相连 思路:完全图,prim算法的效率取决于节点数,适用于稠密图.用prim求解. p.q间距离设为0即可,最后输出时加上p.q间的距离 pri ...

  6. HDU 4463 Outlets (最小生成树)

    题意:给定n个点坐标,并且两个点已经连接,但是其他的都没有连接,但是要找出一条最短的路走过所有的点,并且路线最短. 析:这个想仔细想想,就是应该是最小生成树,把所有两点都可以连接的当作边,然后按最小生 ...

  7. HDU 1301Jungle Roads(最小生成树 prim,输入比较特殊)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1301 Jungle Roads Time Limit: 2000/1000 MS (Java/Oth ...

  8. hdu 4463 Outlets

    #include<bits/stdc++.h> using namespace std; double x[100+5],y[100+5]; double e[100+5][100+5]; ...

  9. MST(最小生成树)——Prim算法——HDU 1879-继续畅通工程

    Prim算法很好理解,特别是学完了迪杰斯特拉算法之后,更加能理解Prim的算法思想 和迪杰斯特拉算法差不多,由于最后要形成连通图,故任意指定一个点,作为初始点,遍历所有点,以当前最小权值的点(和迪杰斯 ...

随机推荐

  1. LeeCode-Number of 1 Bits

    Write a function that takes an unsigned integer and returns the number of ’1' bits it has For exampl ...

  2. HDOJ-1012 u Calculate e(水)

    http://acm.hdu.edu.cn/showproblem.php?pid=1012 简单套公式 # include <stdio.h> double Factorial(doub ...

  3. HBase 4、Phoenix安装和Squirrel安装

    描述 现有hbase的查询工具有很多如:Hive,Tez,Impala,Shark/Spark,Phoenix等.今天主要记录Phoenix. phoenix,中文译为“凤凰”,很美的名字.Phoen ...

  4. android ANR 案例分析

    案例1:关键词:ContentResolver in AsyncTask onPostExecute, high iowait Process:com.android.email Activity:c ...

  5. Ffmpeg和SDL创建线程(转)

    Spawning Threads Overview Last time we added audio support by taking advantage of SDL's audio functi ...

  6. FP-Growth算法之频繁项集的挖掘(python)

    前言: 关于 FP-Growth 算法介绍请见:FP-Growth算法的介绍. 本文主要介绍从 FP-tree 中提取频繁项集的算法.关于伪代码请查看上面的文章. FP-tree 的构造请见:FP-G ...

  7. JNI_最简单的Java调用C/C++代码

    JNI_最简单的Java调用C/C++代码 JNI.是Java Native Interface的简称,中文是"Java本地调用".通过这种技术能够做到下面两点: Java程序中的 ...

  8. iOS 字体设置

    使用无衬线字体 body {     font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif; }  iOS 4 ...

  9. H5单页面架构:requirejs + angular + angular-route

    说到项目架构,往往要考虑很多方面: 方便.例如使用jquery,必然比没有使用jquery方便很多,所以大部分网站都接入类似的库: 性能优化.包括加载速度.渲染效率: 代码管理.大型项目需要考虑代码的 ...

  10. MySQL ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO

    MySQL安装完server端和客户端后,登录Mysql时报错:[root@rhel204 MySQL 5.6.23-RMP]# mysqlERROR 2002 (HY000): Can't conn ...