zoukankan      html  css  js  c++  java
  • NowCoder栗酱的连通图(最小生成树, 结论)

    链接:

    https://www.nowcoder.com/acm/contest/52/K

    题意:

    给定n个点,每个点有自己的权值, 然后让你添加n-1条边,使其边权和最大, 边权的定义是两点的点权和除2。

    分析:

    一开始我想到的是裸的最小生成树, 用优先队列优化的prim算法200ms过了,复杂度是O(mlogn),m是边数,n是点数 ,代码如下

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 struct edge{int to, dis; edge(int _to, int _dis):to(_to), dis(_dis){}};
     4 const int maxn = 1e3 + 7;
     5 const int maxm = maxn * maxn;
     6 vector<edge> G[maxn];
     7 int a[maxn];
     8 int n;
     9 int prim(){
    10     int ans = 0;
    11     int dis[maxn];
    12     bool vis[maxn];
    13     priority_queue<pair<int, int>, vector<pair<int, int> >, less<pair<int, int> > > q;
    14     memset(dis, -1, sizeof(dis));
    15     memset(vis, 0, sizeof(vis));
    16     for(int i = 0; i < G[0].size(); i++){
    17         int v = G[0][i].to, d = G[0][i].dis;
    18         dis[v] = d;
    19         q.push(make_pair(d,v));
    20     }
    21     dis[0] = 0, vis[0] = 1;
    22     while(!q.empty()){
    23         int u = q.top().second, d = q.top().first;
    24         q.pop();
    25         if(vis[u]) continue;
    26         vis[u] = 1;
    27         ans += d;
    28         for(int i = 0; i < G[u].size(); i++){
    29             int v = G[u][i].to, d = G[u][i].dis;
    30             if(!vis[v] && (dis[v] < d)){//注意prim的松弛条件别写错
    31                 dis[v] = d;
    32                 q.push(make_pair(dis[v], v));
    33             }
    34         }
    35     }
    36   
    37     return ans;
    38 }
    39 int main(){
    40     int T;
    41     scanf("%d", &T);
    42     while(T--){
    43         for(int i = 0; i < maxn; i++) G[i].clear();
    44         scanf("%d", &n);
    45         for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    46         for(int i = 0; i < n; i++)
    47         for(int j = i + 1; j < n; j++){
    48             G[i].push_back(edge(j, (a[i] + a[j]) / 2));
    49             G[j].push_back(edge(i, (a[i] + a[j]) / 2));
    50         }
    51         cout << prim() << "
    ";
    52     }
    53     return 0;
    54 }
    prim优先队列

    但是看了别人的时间后发现都是10ms以内的,以上的算法大约在n去到10^3已经极限了, 因为完全图边数是n*(n-1)/2

    想了想其实这题有个简单的结论,就是“除权值最大的点外,每个点都与权值最大的点相连”,这样可以保证边权取到最大, 而且刚好n-1条边。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4     int a[1003];
     5     int n, T;
     6     scanf("%d", &T);
     7     while(T--){
     8         scanf("%d", &n);
     9         for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    10         sort(a, a+n);
    11         int ans = 0;
    12         for(int i = 0; i < n - 1; i++) ans += (a[n-1] + a[i]) / 2;
    13         printf("%d
    ", ans);
    14     }
    15     return 0;
    16 }
    结论
  • 相关阅读:
    Bypass WAF
    一种简单的hook方法--LD_PRELOAD变量
    Linux C:access()时间条件竞争漏洞
    环境变量法提权
    sudo-tcpdump提权法
    asynico转载
    pychar 2020.1.2激活
    临时mysql 链接池
    python pip 使用阿里云镜像安装库
    zookeeper kafaka 临时保存
  • 原文地址:https://www.cnblogs.com/Jadon97/p/8048405.html
Copyright © 2011-2022 走看看