以(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. Fragment与Activity相互传递数据:

    Activity向Fragment传递数据:在Activity中创建Bundle数据包,并调用Fragment的setArguments(Bundle bundle)方法即可将Bundle数据包传给F ...

  2. Redis Clients Handling

    This document provides information about how Redis handles clients from the point of view of the net ...

  3. First Missing Positive 解答

    Question Given an unsorted integer array, find the first missing positive integer. For example,Given ...

  4. apache http配置https

    <一,Lamp系统搭建> yum install httpd httpd-devel mysql mysql-server mysql-devel php php-mysql php-co ...

  5. cenos 7 安装php7

    1. CentOS/RHEL 7.x: rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm ...

  6. 在php添加mongo过程中出现的mongo.so: > undefined symbol: php_json_encode in Unknown on line 0. After installation mongo driver for php 的错误

    3 down vote my system is centos 6.3. I got the problem solved. vim /etc/php.ini then add extension=j ...

  7. 擅长排列的小明 II(找规律)

    擅长排列的小明 II 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 小明十分聪明,而且十分擅长排列计算. 有一天小明心血来潮想考考你,他给了你一个正整数n,序列1,2, ...

  8. STL 整理(map、set、vector、list、stack、queue、deque、priority_queue)(转)

    向量(vector) <vector> 连续存储的元素<vector> Vector<int>c; c.back()    传回最后一个数据,不检查这个数据是否存在 ...

  9. Android应用程序窗口(Activity)实现框架简要介绍和学习计划

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8170307 前面我们学习了SurfaceFli ...

  10. java学习笔记day07

    1.throwable下面的子类分为两大类:Error 和 Exception 2.如果方法上有throws Exception,则必须对异常进行处理:  try{    需要检测异常代码     } ...