POJ 2349(Kruskal) Arctic Network

题目

The Department of National Defence (DND) wishes to connect several northern outposts by a wireless network. Two different communication technologies are to be used in establishing the network: every outpost will have a radio transceiver and some outposts will in addition have a satellite channel.
Any two outposts with a satellite channel can communicate via the satellite, regardless of their location. Otherwise, two outposts can communicate by radio only if the distance between them does not exceed D , which depends of the power of the transceivers. Higher power yields higher D but costs more. Due to purchasing and maintenance considerations, the transceivers at the outposts must be identical; that is, the value of D is the same for every pair of outposts.

Your job is to determine the minimum D required for the transceivers. There must be at least one communication path (direct or indirect) between every pair of outposts.

Input

The first line of input contains N , the number of test cases. The first line of each test case contains 1S100, the number of satellite channels, and SP500 , the number of outposts. P lines follow, giving the (x,y) coordinates of each outpost in km (coordinates are integers between 0 and 10,000).

Output

For each case, output should consist of a single line giving the minimum D required to connect the network. Output should be specified to 2 decimal points.

Sample Input

1
2 4
0 100
0 300
0 600
150 750

Sample Output

212.13

题意

P个站点,每个站点之间都有权重(两点之间的距离),给出 S 个卫星,如果两个站点之间用卫星连接,那么它们之间的权值将变为0,给出每个站点的坐标,需要保证:

1、任意两个站点都可以联系(直接或者间接);

2、使任意两站点的最大通信花费变得最小。

需要输出最大的通信花费。

思路

最小生成树的问题,利用 Kruskal 算法,它的目的是建立一个最小生成树,但是模板中最后返回的是最小生成树的权值和。它的第一步是给所有边按照从小到大的顺序排列。这一步可以直接调用库函数 qsort 或者 sort 。记每条边为 (u,v)
有两种情况:1、 u v 在同一个连通分量中,加入 (u,v) 会形成环,不能选择。
2、如果 u ,v不在同一个连通分量中,那么加入 (u,v) 一定是最优解。
现在需要知道三件事:

1、在一张全联通图的最小生成树中,新增一条权为0的边,新增加的边则取代形成的环中的另外一条边形成新的最小生成树。

2、在一张全连通图中,若在其最小生成树中挑选 S 个节点,在其两两间添加权为 0 的边,则新生成的边必定可以取代生成的环中的 S1 个边构成新的最小生成树。选择 S 个节点,得到的最小生成树由 S1 条权为 0 的边构成,接下来将剩下的点加入最小生成树里,只需要添加 (N1)(S1)=NS 条边。

3、在一张全连通图中,新增的一条边可以和任意一条边构成环。

于是,利用 Kruskal 算法在求最小生成树的时候,如果 u v 不在同一个连通分量里,那就通过 pair 建立坐标将 ans 放入 vector 数组里,因为 ans 在过程中已经是从小到大排好的,最后需要输出的就是 ans[NS2]

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<cstdlib>
#include<functional>
#include<climits>
#include<cctype>
#include<iomanip>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define INF 0x3f3f3f3f
#define mod 1e9+7
#define clr(a,x) memset(a,x,sizeof(a))
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
const double eps = 1e-6;
int fa[250005];
vector<double> ans;
void init(int n)
{
    for(int i=0;i<=n;i++)
    {
        fa[i]=i;
    }
}
int find(int x)
{
    if(fa[x]!=x)
        fa[x]=find(fa[x]);
    return fa[x];
}
void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y)
        return ;
    else
        fa[x]=y;
}
bool same(int x,int y)
{
    return find(x)==find(y);
}
vector <pair<double,PII> > G;
void add_egde(int u,int v,double d)
{
    G.pb(mp(d,mp(u,v)));
}
void Kruskal(int n)

{
    init(n);
    sort(G.begin(),G.end());
    int m=G.size();
    int num=0;
    for(int i=0;i<m;i++)
    {
        pair<double,PII> p=G[i];
        int x=p.second.first;
        int y=p.second.second;
        double d=p.first;
        if(!same(x,y))
        {
            unite(x,y);
            num++;
            ans.pb(d);  //将边权放入vector中
        }
        if(num==n-1)
            break;
    }
}
double dis(double x1,double y1,double x2,double y2)
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void joint(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x!=y)
    {
        fa[x]=y;
    }
}
int main()
{
    int t;
    cin>>t;
    int s,p;
    while(t--)
    {
        pair<double,double> P[505];
        G.clear();
        ans.clear();
        cin>>s>>p;
        for(int i=0;i<p;i++)
        {
            cin>>P[i].first>>P[i].second;
        }
        for(int i=0;i<p;i++)
            for(int j=i+1;j<p;j++)
            {
                double d=dis(P[i].first,P[i].second,P[j].first,P[j].second);
                add_egde(i,j,d);
                add_egde(j,i,d);
            }
        Kruskal(p);
        printf("%.2f\n",ans[p-s-1]);
    }
    return 0;
}

总结

自己理解好久以及在大佬的帮助下最终还是做出了,太菜了。。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值