• Codeforces 745C:Hongcow Builds A Nation(并查集)


    http://codeforces.com/problemset/problem/744/A

    题意:在一个图里面有n个点m条边,还有k个点是受限制的,即不能从一个受限制的点走到另外一个受限制的点(有路径相连),问在这样的图里面遵守这样的规则可以最多添加几条边。

    思路:这种题之前在做强连通的时候很常见,于是就写了tarjan。。醒来后发现不用这么复杂,直接用并查集就可以做了。

    1、对于每一个连通块,最多可以加上n*(n-1)/2条边。

    2、对于受限制的连通块,取出一个点数最多的,和不受限制的块相连。

    3、对于不受限制的连通块,两两之间可以相连。

    4、由于有重复,所以减去初始的m条边。

    并查集:

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <string>
     6 #include <cmath>
     7 #include <queue>
     8 #include <vector>
     9 #include <map>
    10 #include <set>
    11 using namespace std;
    12 #define INF 0x3f3f3f3f
    13 #define N 100010
    14 typedef long long LL;
    15 int sum[1010], c[1010], fa[1010], tag[1010];
    16 vector<int> vec;
    17 
    18 int Find(int x) {
    19     if(x == fa[x]) return x;
    20     return fa[x] = Find(fa[x]);
    21 }
    22 
    23 void Merge(int x, int y) {
    24     x = Find(x), y = Find(y);
    25     if(x == y) return ;
    26     fa[x] = y;
    27     sum[y] += sum[x];
    28 }
    29 
    30 int main() {
    31     int n, m, k;
    32     cin >> n >> m >> k;
    33     for(int i = 1; i <= k; i++) cin >> c[i];
    34     for(int i = 1; i <= n; i++) fa[i] = i, sum[i] = 1;
    35     for(int i = 1; i <= m; i++) {
    36         int u, v;
    37         cin >> u >> v;
    38         Merge(u, v);
    39     }
    40     int ans = -m, ma = 0;
    41     for(int i = 1; i <= k; i++) tag[Find(c[i])] = 1; // 标记受限制的块
    42     for(int i = 1; i <= n; i++) {
    43         if(fa[i] == i) {
    44             if(tag[i]) ma = max(sum[i], ma);
    45             else vec.push_back(sum[i]);
    46             ans += sum[i] * (sum[i] - 1) / 2; // 每个连通块里面最大边数
    47         }
    48     }
    49     int sz = vec.size();
    50     for(int i = 0; i < sz; i++) {
    51         for(int j = i + 1; j < sz; j++) {
    52             ans += vec[i] * vec[j]; // 不受限制的连通块之间连边
    53         }
    54         ans += vec[i] * ma; // 受限制的取最大的和不受限制的连边
    55     }
    56     cout << ans << endl;
    57     return 0;
    58 }

    tarjan:

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <cstring>
      5 #include <string>
      6 #include <cmath>
      7 #include <queue>
      8 #include <vector>
      9 #include <map>
     10 #include <set>
     11 #include <stack>
     12 using namespace std;
     13 #define INF 0x3f3f3f3f
     14 #define N 100010
     15 typedef long long LL;
     16 struct node {
     17     int u, v, nxt;
     18 }edge[2*N];
     19 struct P {
     20     int id, num;
     21 }p[1010];
     22 int head[1010], tot, cnt, num;
     23 int belong[1010], dfn[1010], low[1010], c[1010], vis[1010];
     24 stack<int> sta;
     25 vector<int> v1, v2;
     26 
     27 void add(int u, int v) {
     28     edge[tot].v = v; edge[tot].nxt = head[u]; head[u] = tot++;
     29 }
     30 
     31 void tarjan(int u) {
     32     dfn[u] = low[u] = ++cnt;
     33     vis[u] = 1; sta.push(u);
     34     for(int i = head[u]; ~i; i = edge[i].nxt) {
     35         int v = edge[i].v;
     36         if(!dfn[v]) {
     37             tarjan(v);
     38             if(low[v] < low[u]) low[u] = low[v];
     39         } else if(vis[v]) {
     40             if(dfn[v] < low[u]) low[u] = dfn[v];
     41         }
     42     }
     43     if(dfn[u] == low[u]) {
     44         ++num;
     45         while(true) {
     46             int v = sta.top(); sta.pop();
     47             belong[v] = num; vis[v] = 0;
     48             if(v == u) break;
     49         }
     50     }
     51 }
     52 
     53 int main() {
     54     int n, m, k;
     55     scanf("%d%d%d", &n, &m, &k);
     56     for(int i = 0; i < k; i++) scanf("%d", c + i);
     57     memset(head, -1, sizeof(head));
     58     memset(vis, 0, sizeof(vis));
     59     tot = num = cnt = 0;
     60     for(int i = 0; i < m; i++) {
     61         int u, v;
     62         scanf("%d%d", &u, &v);
     63         add(u, v); add(v, u);
     64     }
     65     for(int i = 1; i <= n; i++)
     66         if(!dfn[i]) tarjan(i);
     67     v1.clear(); v2.clear();
     68     for(int i = 1; i <= num; i++) {
     69         for(int j = 1; j <= n; j++) {
     70             if(belong[j] == i) {
     71                 p[i].num++;
     72             }
     73         }
     74     }
     75     for(int i = 0; i < k; i++)
     76         p[belong[c[i]]].id = 1;
     77     for(int i = 1; i <= num; i++) {
     78         if(p[i].id == 1) v1.push_back(p[i].num);
     79         else v2.push_back(p[i].num);
     80     }
     81     sort(v1.begin(), v1.end());
     82     sort(v2.begin(), v2.end());
     83     int sz = v1.size();
     84     int szz = v2.size();
     85     LL ans = 0;
     86     for(int i = 0; i < szz; i++)
     87         ans += v1[sz-1] * v2[i];
     88     for(int i = 0; i < szz; i++) {
     89         for(int j = i + 1; j < szz; j++) {
     90             ans += v2[i] * v2[j];
     91         }
     92         ans += v2[i] * (v2[i]-1) / 2;
     93     }
     94 
     95     for(int i = 0; i < sz; i++)
     96         ans += (v1[i]-1) * v1[i] / 2;
     97     ans -= m;
     98     printf("%I64d
    ", ans);
     99     return 0;
    100 }
    101 
    102 /*
    103 8 4 2
    104 4 5
    105 1 2
    106 6 7
    107 7 8
    108 2 4
    109 */
  • 相关阅读:
    u3d Mecanim动画
    四元数的共轭和逆
    c++ 单例模式
    GVIM、VIM
    Linux磁盘管理——虚拟文件系统
    Linux磁盘管理——MBR 与 GPT
    Link monitoring
    Linux高级网络设置——将多个网卡设置成一个网卡
    Linux高级网络设置——给网卡绑定多个IP
    DNS原理极限剖析
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6193825.html
Copyright © 2020-2023  润新知