P1265 公路修建

复习prim算法系列

虽然prim跟dij是差不多的,但是两者还是有一点点差别。

就像我这种菜鸡,只会dij,结果写出来的prim奇怪得很。

这道题我还特意写了个堆优化,但是也没快到那儿去。。。


首先如何看出这是最小生成树的裸题?

  1. 在每一轮中,每个城市选择一个与它最近的城市,申请修建通往该城市的公路。这就是prim的做法。

  2. 如果三个或以上的城市申请修建的公路成环。如下图,A申请修建公路AB,B申请修建公路BC,C申请修建公路CA。则政府将否决其中最短的一条公路的修建申请。

第二个条件有点东西,它确保答案是没有环的。

但是这为什么就是最小生成树呢?

显然,因为他们想修建这些公路,所以AB>AC,BC>BA,CA>CB。

合起来就是AB>=AC,BC>=AB,AC>=BC。

当且仅当这三者相等的时候不等式组成立,而随便去掉一个都没有影响。

所以接下来的任务就是套上prim算法了。

当然不用kruskal算法了,因为边太多了!

这里使用堆优化的prim,还可以。

代码:

#include<cstdio>
#include<cmath>
#include<queue>
const int maxn = 5005;
struct Nodes
{
    double x, y;
} s[maxn];
double dist[maxn];
bool vis[maxn];
double ans;
int n;
struct HeapNodes
{
    double dist; int u;
    HeapNodes(double dist, int u): dist(dist), u(u){}
    bool operator < (const HeapNodes &rhs) const
    {
        return dist > rhs.dist;
    }
};
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar();
    return s * ans;
}
double dis(int a, int b)// 直接人工算距离就可以了
{
    return sqrt((s[a].x - s[b].x) * (s[a].x - s[b].x) + (s[a].y - s[b].y) * (s[a].y - s[b].y));
}
void prim()
{
    std::priority_queue<HeapNodes> heap;
    dist[1] = 0; vis[1] = true;
    for(int i = 2; i <= n; i++)
    {
        dist[i] = dis(1, i);
        heap.push(HeapNodes(dist[i], i));// 这是初始化阶段,用1开拓所有的节点
    }
    while(!heap.empty())
    {
        HeapNodes u = heap.top(); heap.pop();
        if(vis[u.u]) continue;// vis过当然就忽略了
        ans += u.dist;// 添加进来
        vis[u.u] = true;
        for(int i = 1; i <= n; i++)
        {
            if(!vis[i])
            {
                if(dis(u.u, i) < dist[i])// 注意这里的写法,我之前写错了
                {
                    dist[i] = dis(u.u, i);
                    heap.push(HeapNodes(dist[i], i));
                }
            }
        }
    }
}
int main()
{
    n = read();
    for(int i = 1; i <= n; i++) scanf("%lf%lf", &s[i].x, &s[i].y);
    prim();
    printf("%.2lf\n", ans);
    return 0;
}
posted @ 2018-10-22 22:09  Garen-Wang  阅读(185)  评论(0编辑  收藏  举报