码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-12-18 12:25:46      阅读:226      评论:0      收藏:0      [点我收藏+]

标签:turn   names   log   eof   mem   math   scanf   code   else   

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(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\n", 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 */

 

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

标签:turn   names   log   eof   mem   math   scanf   code   else   

原文地址:http://www.cnblogs.com/fightfordream/p/6193825.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!