以(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. ListView中分割线的设置

    1.在布局文件中ListView元素中通过属性设置 android:divider="#fffff" 分割线颜色 android:dividerHeight="1px&q ...

  2. spring3.0事务的配置

    第一种配置方法:基于XML的事务管理 这种方法不需要对原有的业务做任何修改,通过在XML文件中定义需要拦截方法的匹配即可完成配置,要求是,业务处理中的方法的命名要有规律,比如setXxx,xxxUpd ...

  3. mongodb导入导出备份恢复

    mongodb数据库同样离不开必要的维护,如备份.恢复.导入.导出. 其实备份和恢复比导入和导出要方便些,而且一般不会出错,所以大部分时候使用备份和恢复操作就可以了 1. 备份Mongodb mong ...

  4. 用Python实现九九乘法表

    1.用“#”组成的矩形的实现 代码 eight = int(input("Height:")) #用户输入高度 width = int(input("Width:&quo ...

  5. UGUI Silder

    来我们看看这个像温度计的控件, 比如音量面板声音大小的控制.它是一个组合型控件由多个Image 和一个Slider组合而成 它的核心是Slider组件实现的. 简单介绍下Slider组件的属性: Fi ...

  6. Bitmap工具类

    一直在使用的一个Bitmap工具类 处理Bitmap和ImageView对象,实现了下面功能: 1.saveBitmap: 把Bitmap对象持久存储到SD卡或手机内存. 2.getViewBitma ...

  7. Dreamweaver8卡死打开初始化(缓存重建)失败的解决的方法

    无论是中文版的dreamweaver 8,还是英文版本号的dw8或绿色版本号的DW8,都可能出现打开时卡死无法启动的情况,这个bug的出现是由于先前你以前在使用dreamweaver 8的时候,定义了 ...

  8. Akka边学边写(2)-- Echo Server

    EchoServer 上篇文章里,我们用Akka写了一个简单的HelloWorld样例,对Akka(以及Actor模式)有了初步的认识.本文将用Akka写一个EchoServer,看看在Actor的世 ...

  9. Photoshop 批量处理图片

    不论什么你想反复进行的操作都能够通过创建 Photoshop 批处理程序来完毕.比如.你想批量改变图片的大小,就能够通过下面操作来实现. 1.打开随意一张图片,在动作面板中,点击新建button 2. ...

  10. MFC多线程内存泄漏问题&amp;解决方法

    在用visual studio进行界面编程时(如MFC),前台UI我们能够通过MFC的消息循环机制实现.而对于后台的数据处理.我们可能会用到多线程来处理. 那么对于大多数人(尤其是我这样的菜鸟),一个 ...