以(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. WPF & ArcGIS Engine三维开发入门攻略

    原文 http://www.cnblogs.com/Realh/archive/2010/12/14/1906112.html 前些日子在做ESRI的开发大赛,从刚开始接触ArcGIS Engine( ...

  2. Android中通过代码获取arrays.xml文件中的数据

    android工程res/valuse文件夹下的arrays.xml文件中用于放各种数组数据,比如字符串数组.整型数组等,数组中的数据可能是具体的值,也有可能是对资源数据的引用,下面针对这两种情况通过 ...

  3. Java中的native方法

    博客引用地址:Java中的native方法 今天花了两个小时把一份关于什么是Native Method的英文文章好好了读了一遍,以下是我依据原文的理解. 一. 什么是Native Method 简单地 ...

  4. YII学习(第一天)

    #Apache # 设置文档根目录为 "basic/web" DocumentRoot "path/to/basic/web" <Directory &q ...

  5. Java获取客户端真实IP地址的两种方法

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...

  6. 3GP文件格式研究

    需要看的文档 http://www.3gpp.org/ftp/Specs/archive/26_series/ 3GPP TS 26.233 3GPP TS 26.243 3GPP TS 26.244 ...

  7. MVC学习 (一)

    在学习MVC之前对asp.net MVC已经有了一些了解,但是还是有很多的疑问,接下来我慢慢来看书学习并带着问题写博客以作记录. 1.MVC是什么? 2.Asp.net MVC和传统的Asp.net ...

  8. SQL查询语句47题

    select * from student select * from score --select * from grade select * from course select * from t ...

  9. 什么时候会刷新备库控制文件refresh the standby database control file?

    通过合理的设置,对于Primary的绝大数操作,都是可以传递到Physical Standby,datafile的操作是通过STANDBY_FILE_MANAGEMENT参数来控制的,但是即使STAN ...

  10. 敏捷软件开发之TDD(一)

    测试驱动开发即TDD是敏捷软件开发方法的重要组成部分.TDD是从极限编程中发展而来,它既可以用在设计时也可以用在开发实践中.TDD把业务需求转化为可以运行的测试代码并具有如下的优点1.TDD从一开始就 ...