Avito Cool Challenge 2018:D. Maximum Distance (最小生成树)

题目链接

题意 :

给出一个联通图和一些特殊的点,现在定义cost(u,v)为一条从u到v的路径上面边权的最大值 , 

定义dis(u,v) 为从u到v 路径上面cost 的最小值

然后求所有特殊点到其他特殊点的最大距离

题解:

做这题前,首先思考一件事情,对于一颗树来说点到点的距离是不是就是树上面路径的边权最大值

我们来证明一下:假设在最小生成树上面的路径cost为w1,另外在原图中还有一条路径从u到v,其cost为w2,那么必然有w2>w1的。那么我们最后的dis一定是w1。

那么我们现在的目标就是求特殊点到特殊点之间的最大距离。注意一下这里是从一个特殊点到其它所有特殊点的最大距离

我们根据Kruskal 算法的构建过程 , 在构建树的时候是先构造小的边的 , 所以我们就可以在Kruskal加边的时候更新答案 , 

我们假设现在有两个集合,现在将其连接起来,当满足两个集合里面都有特殊点时我们就可以更新答案了,否则就不行。

转载 现在还有一些问题没有解决 , 待后跟新

#include<bits/stdc++.h>
using namespace std;

const int maxn = 100001;//最大点数
int c[maxn], N,M,k;//并查集使用
int cnt;
bool a[maxn];
int VAL[maxn];
struct EDGE{
    int from, to, w;
    bool operator < (const EDGE &rhs) const{
        return this->w < rhs.w;
    };
}Edge[maxn];//储存边的信息,包括起点/终点/权值

inline void init()
{
    for(int i=0; i<=N; i++)
        c[i] = i;
    cnt = 0;
}

inline void AddEdge(int from, int to, int weight)
{
    Edge[cnt].from = from;
    Edge[cnt].to   = to;
    Edge[cnt].w    = weight;
    cnt++;
}

int Findset(int x)
{
    int root = x;
    while(c[root] != root)
        root = c[root];

    int idx;
    while(c[x] != root){ /// 路径压缩
        idx = c[x];
        c[x] = root;
        x = idx;
    }
    return root;
}

int Kruskal()//传入点数,返回最小生成树的权值,如果不连通返回-1
{
    sort(Edge,Edge+cnt);
    int EdgeCnt=0;//计算加入的边数
    int Cost=0;
     int MAX=0;
    for(int i=0;i<cnt;i++){
        int u=Edge[i].from;
        int v=Edge[i].to;
        int w=Edge[i].w;
        int R1 = Findset(u);
        int R2 = Findset(v);
        if(R1==R2) continue;
        c[R1]=R2;
        if(a[u]) VAL[R1]++;//标记的点
        if(a[v]) VAL[R2]++;
        if(VAL[R1] && VAL[R2] )//如果标记的点都有
        MAX=w;
       VAL[R2]+=VAL[R1];
        EdgeCnt++;
        if(EdgeCnt==N-1) break;
    }
    if(EdgeCnt<N-1) return -1;//不连通
    else return MAX;
}


int main()
{
        scanf("%d%d%d",&N,&M,&k);
        init();
        int Val;
        for(int i=1 ; i<=k ; i++)
        {
             scanf("%d",&Val);
             a[Val]=1;
        }


         for(int i=1 ; i<=M ; i++)
         {   int u,v,w;
             scanf("%d%d%d",&u,&v,&w);
             AddEdge(u,v,w);
         }
         int P=Kruskal();
         for(int i=1 ; i<=k ; i++)
         printf("%d ",P);
      //  printf("%d\n", Kruskal());

    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/shuaihui520/p/10136769.html