最小生成树——(性质)其最大边权为生成树中最大边权最小的——(例题)承包池塘的青蛙

最小生成树不仅可以得到最小的权值之和,其最大边权为生成树中最大边权最小的。

*一道例题

1:承包池塘的青蛙
查看 提交 统计 提问
总时间限制: 1000ms 内存限制: 128000kB
描述
某池塘有N片荷叶, M只青蛙, 青蛙喜欢在荷叶之间跳来跳去.

给出青蛙们的最大可跳跃的距离Ci, 以及荷叶的坐标, 当忽略荷叶的直径.如果两片荷叶A和B间的距离小于某只青蛙F的最大可跳跃距离时, 可认为青蛙F可以从A跳到B, 也可以从B跳到A.

求能够从任意荷叶出发, 仅通过跳跃就能到达其它任意荷叶的青蛙个数.

输入
第一行一个整数, 表示M(2<=M<=500)
第二行为M个整数, 依次表示Ci(每个整数值在1—1000之间)
第三行为一个整数, 表示N(2<=N<=1000)
第四行至第N+3行, 每行两个数, 分布表示N个荷叶的坐标(横纵坐标均为整数, 范围为:-10000–10000)
输出
输出只有一行, 即所求满足条件的青蛙只数.
样例输入
4
100 200 300 400
6
0 0
100 0
100 200
-100 -100
-200 0
200 200
样例输出
3

疑问在于:为什么最小生成树的最长边是青蛙跳跃距离的下限?

首先,青蛙要到达所有节点,生成的图一定是经过所有点的。
存在无数个这样的图,而决定青蛙能否成功的只有这张图的最长边;
该图可能有环也可能无环,而有环图可以删掉某些边变为无环图,最长边只可能变小了或不变->最长边下线必定会在无环图(生成树)中找到;

确定了路线一定为生成树,接下来讨论为何是最小生成树。
我们用反证法:存在最小生成树,最长边为e;假设存在一个一般生成树,最长边eb且eb

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
class edge
{
    public:
        edge(int v1, int v2, int weigh)
        {
            _v1 = v1;
            _v2 = v2;
            _weigh = weigh;
        }
        int either()
        {
            return _v1;
        }
        int other(int v)
        {
            if(v == _v1) return _v2;
            return _v1;
        }
        int weigh()
        {
            return _weigh;
        }
    private:
        int _v1;
        int _v2;
        int _weigh;
};
struct cmp
{
    bool operator()(edge a, edge b)
    {
        return a.weigh() > b.weigh();
    }
};
class mst
{
    public:
        mst(int v)
        {
            _v = v;
            _adj = new vector [v];
            _marked = new bool[v];
            memset(_marked, false, sizeof(_marked));
            _max = 0;
        }
        void insert(edge e)
        {
            int v1 = e.either();
            int v2 = e.other(v1);
            _adj[v1].push_back(e);
            _adj[v2].push_back(e);
        }
        void build(int s)
        {
            visit(s);
            while(!q.empty()){
                edge cur = q.top();
                q.pop();
                int v1 = cur.either();
                int v2 = cur.other(v1);
                if(_marked[v1] && _marked[v2]) continue;
                if (cur.weigh() > _max) _max = cur.weigh();
                if(!_marked[v1]) visit(v1);
                else if(!_marked[v2]) visit(v2);
            }
        }
        void visit(int p)
        {
            _marked[p] = true;
            vector  nei = _adj[p];
            int len = nei.size();
            for(int i = 0; i < len; i++){
                q.push(nei[i]);
            }
        }
        int max()
        {
            return _max;
        }
    private:
        priority_queue vector, cmp> q;
        bool* _marked;
        vector * _adj;
        int _v;
        int _max;
};
int main()
{
    int m;
    cin >> m;
    int frog[505];
    for(int i = 0; i < m; i++){
        cin >> frog[i];
    }
    int n;
    cin >> n;
    int co[1005][2];
    for(int i = 0; i < n; i++){
        cin >> co[i][0] >> co[i][1];
    }
    mst pond(n);
    int numOfEdge = (n * (n - 1)) / 2;
    for(int j = 0; j < n - 1; j++){
        for(int k = j + 1; k < n; k++){
            int x1 = co[j][0];
            int y1 = co[j][1];
            int x2 = co[k][0];
            int y2 = co[k][1];
            int weigh2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
            edge cur(j, k, weigh2);
            pond.insert(cur);
        } 
    }
    pond.build(0);
    int max = pond.max();
    int count = 0;
    for(int i = 0; i < m; i++){
        if(frog[i] * frog[i] >= max) count++;
    }
    cout << count << endl;
    return 0;
}

你可能感兴趣的:(编程,最小生成树)