POJ 2349 Arctic Network

本文详细解析了POJ2349题目中的最小生成树算法实现,通过Prim算法寻找最优解,并介绍了如何利用卫星频道优化网络连接成本的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ 2349 Arctic Network

1 算法

  1. prim求最小生成树;
  2. 将生成树最长的边用2卫星频道连接(如果s不允许,则最小D为该边长);
  3. 从剩余边中找出最长的(x,y),其将最小生成树断开为2个集合,其中一个集合set1中有拥有卫星频道的点,另一个集合set2则没有这样的点,x和y分别处于一个集合中,为处于set2的点配置1个卫星频道;
  4. 若s!=0,重复3操作,否则,剩余边中最长边长为最小D

2 易错点和优化

易错点: 每次为剩余边中最长边的两端点都配置卫星频道(如果未配置), 如下图(括号内为边长),当01、03已配置卫星频道, 则剩余边中最长边为02----(8)----04,要避免D>8,则需在04配置卫星频道,无需在02也配置。

                               01                               
                 /-----(2)-----/\-----(9)-----\                 
               02                              03               
         /-(8)-/\-(1)-\                         \-(6)-\         
       04              05                              07       

优化: 刚开始时,最长边两端点配置卫星频道后(剩余s-2个卫星频道), 接下来每配置一个卫星频道,则减少一条极长边,当s-2个卫星频道用完后, 则剩余边中最长边为最开始的第(1+s-2+1 = s)长, 故D的最小值直接输出第s长的边长,不需模拟。

3 代码

3.1 AC的代码

#include <algorithm>
#include <iomanip>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int s, p;
int n;
double lg[500][500];
double x[500], y[500];
double dis[500];
//bool inset[500];
int father[500];
struct way
{
        int x, y;
        double len;
};
struct way q[500];

double len(int i, int j)
{
        return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
void read_data()
{
        cin >> s >> p;
        for (int i = 0; i < p; ++i)
        {
                cin >> x[i] >> y[i];
                for (int j = 0; j < i; ++j)
                {
                        lg[i][j] = len(i, j);
                        lg[j][i] = lg[i][j];
                }
        }
}

bool cmp(const struct way &a, const struct way &b)
{
        return a.len > b.len;
}
/*
int find(int i)
{
        int sou, tmp;
        for (sou = i; father[sou] >= 0; sou = father[sou]);
        while (i != sou)
        {
                tmp = father[i];
                father[i] = sou;
                i = tmp;
        }
        return sou;
}

void unionset(int x, int y)
{
        int s1 = find(x), s2 = find(y);
        if (s1 == -1) 
                father[s2] = s1;
        else
                father[s1] = s2;
}
*/
double prim()
{
        double mindis;
        int x, y;
        int num;
        for (int i = 0; i < p; ++i)
        {
                father[i] = 0;
                dis[i] = lg[0][i];
        }
        dis[0] = -1;
        num = 0;
        while (num != p - 1)
        {
                mindis = 1000000000;
                for (int i = 0; i < p; ++i)
                        if (dis[i] >= 0 && mindis > dis[i]) 
                        {
                                mindis = dis[i];
                                x = i;
                        }
                q[num].x = x;
                q[num].y = father[x];
                q[num].len = mindis;
                num++;
                dis[x] = -1;
                for (int i = 0; i < p; ++i)
                        if (dis[i] >= 0 && dis[i] > lg[x][i])
                        {
                                dis[i] = lg[x][i];
                                father[i] = x;
                        }
        }
        sort(q, q + num, cmp);
        //memset(inset, 0, sizeof(inset));
        if (s == 1) return q[0].len;
        s -= 2;
        //inset[q[0].x] = true;
        //inset[q[0].y] = true;
        //father[q[0].x] = -1;
        //father[q[0].y] = -1;
        num = 1 + s;
        return q[num].len;
/*
        while (s > 0)
        {
                for (int i = 0; i < p; ++i)
                        if (!inset[i]) father[i] = i;
                for (int i = num + 1; i < p - 1; ++i)
                {
                        x = q[i].x;
                        y = q[i].y;
                        if (find(x) != find(y))
                                unionset(x, y);
                }
                x = q[num].x;
                y = q[num].y;
                if (find(x) == -1) 
                {
                        inset[y] = true;
                        father[y] = -1;
                }
                if (find(y) == -1) 
                {
                        inset[x] = true;
                        father[x] = -1;
                }
                s--;
                num++;
        }
        return q[num].len;
        */
}

int main()
{
        cin >> n;
        while (n--)
        {
                read_data();
                printf("%.2f\n", prim());
        }
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值