【HDU 4463 Outlets】最小生成树(prim,kruscal都可)
以(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都可)的更多相关文章
- hdu 4463 Outlets(最小生成树)
Outlets Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submi ...
- HDU—4463 Outlets 最小生成树
In China, foreign brand commodities are often much more expensive than abroad. The main reason is th ...
- HDU 4463 Outlets 【最小生成树】
<题目链接> 题目大意: 给你一些点的坐标,要求你将这些点全部连起来,但是必须要包含某一条特殊的边,问你连起这些点的总最短距离是多少. 解题分析: 因为一定要包含那条边,我们就记录下那条边 ...
- HDU 4463 Outlets(最小生成树给坐标)
Problem Description In China, foreign brand commodities are often much more expensive than abroad. T ...
- hdu 4463 Outlets(最小生成树)
题意:n个点修路,要求总长度最小,但是有两个点p.q必须相连 思路:完全图,prim算法的效率取决于节点数,适用于稠密图.用prim求解. p.q间距离设为0即可,最后输出时加上p.q间的距离 pri ...
- HDU 4463 Outlets (最小生成树)
题意:给定n个点坐标,并且两个点已经连接,但是其他的都没有连接,但是要找出一条最短的路走过所有的点,并且路线最短. 析:这个想仔细想想,就是应该是最小生成树,把所有两点都可以连接的当作边,然后按最小生 ...
- HDU 1301Jungle Roads(最小生成树 prim,输入比较特殊)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1301 Jungle Roads Time Limit: 2000/1000 MS (Java/Oth ...
- hdu 4463 Outlets
#include<bits/stdc++.h> using namespace std; double x[100+5],y[100+5]; double e[100+5][100+5]; ...
- MST(最小生成树)——Prim算法——HDU 1879-继续畅通工程
Prim算法很好理解,特别是学完了迪杰斯特拉算法之后,更加能理解Prim的算法思想 和迪杰斯特拉算法差不多,由于最后要形成连通图,故任意指定一个点,作为初始点,遍历所有点,以当前最小权值的点(和迪杰斯 ...
随机推荐
- 【Android病毒分析报告】 - ZooTiger “集恶意推广、隐私窃取、恶意吸费于一体”
本文章由Jack_Jia编写,转载请注明出处. 文章链接:http://blog.csdn.net/jiazhijun/article/details/11772379 作者:Jack_Jia ...
- PL/SQL --> 动态SQL调用包中函数或过程
动态SQL主要是用于针对不同的条件或查询任务来生成不同的SQL语句.最常用的方法是直接使用EXECUTE IMMEDIATE来执行动态SQL语句字符串或字符串变量.但是对于系统自定义的包或用户自定的包 ...
- java设计模式--行为型模式--备忘录模式
备忘录模式,我们平常所做的备忘录么.还得深深研究哦. 备忘录模式: 备忘录模式 概述 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状 ...
- 2015第10周日CSS—3
CSS各种居中方法 CSS的居中有水平居中和垂直居中,这两种居中又分为行内元素居中和块级元素居中,不同的居中用不同方法. 水平居中 1.行内元素水平居中(文本,图片) 给父层设置 text-align ...
- UESTC_方老师分身 I CDOJ 914
方老师分身 I Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit S ...
- POJ 2263 Heavy Cargo(Floyd + map)
Heavy Cargo Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3768 Accepted: 2013 Descr ...
- hdu 1502 Regular Words_高精度+dp
题意:问按规则排成的串有多少个A(c)>= B(c) >= C(c) 思路:因为写大整数太累,就偷懒了一下直接用java水过 import java.math.BigInteger; im ...
- Js 中常用方法
一.获取唯一值(2014-12-23) function newGuid() { var guid = ""; var n = (((1 + Math.random()) * 0x ...
- Android窗口管理服务WindowManagerService的简要介绍和学习计划
在前一个系列文章中,我们从个体的角度来分析了Android应用程序窗口的实现框架.事实上,如果我们从整体的角度来看,Android应用程序窗口的 实现要更复杂,因为它们的类型和作用不同,且会相互影响. ...
- Linux SSH 远程操作与传送文件
操作系统:centos 6.5 x64 一.远程连接:在进行linux 的 ssh远程操作前,一定要确认linux 是否安装了 openssh-clients,为了方便起见,一般用yum安装即可:# ...