Codeforces Round #385 (Div. 2) Hongcow Builds A Nation —— 图论计数
题目链接:http://codeforces.com/contest/745/problem/C
题意:
给出一张无向图,图中有k个点为特殊点,且图满足:每对特殊点直接没有通路。问:最多能添加多少条边,使得图仍能满足上述条件?
题解:
1.将每个连通块缩成一个集合,这个集合需要记录的信息有:点的个数,以及是否含有特殊点(最多有1个)。
2.根据集合中点的个数,将集合降序排序。
3.首先计算出一个集合内的所有边(完全图),即:num*(num-1)/2;然后挑选点数最大的两个集合,如果这两个集合最多只有一个特殊点,那么意味着他们可以合并,于是合并,共添加了num1*num2条边。
4.由于步骤3计算的是添加边后,总的边数,所以减去初始图的边数,才为添加的边数。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int mod = 1e9+7; 17 const int MAXM = 1e6+10; 18 const int MAXN = 1e4+10; 19 20 struct Node 21 { 22 bool hav; 23 int num; 24 bool operator<(const Node &x)const{ 25 return num>x.num; 26 } 27 }q[MAXN]; 28 29 vector<int>g[MAXN]; 30 bool isgov[MAXN], vis[MAXN]; 31 32 void dfs(int u, int index) 33 { 34 vis[u] = true; 35 q[index].num++; 36 if(isgov[u]) q[index].hav = true; 37 for(int i = 0; i<g[u].size(); i++) 38 if(!vis[g[u][i]]) 39 dfs(g[u][i], index); 40 } 41 42 int main() 43 { 44 int n, m, k; 45 scanf("%d%d%d", &n,&m,&k); 46 memset(isgov, false, sizeof(isgov)); 47 for(int i = 1; i<=n; i++) g[i].clear(); 48 for(int i = 1; i<=k; i++) 49 { 50 int u; 51 scanf("%d", &u); 52 isgov[u] = true; 53 } 54 for(int i = 1; i<=m; i++) 55 { 56 int u, v; 57 scanf("%d%d", &u,&v); 58 g[u].push_back(v); 59 g[v].push_back(u); 60 } 61 62 int index = 0; 63 memset(q, 0,sizeof(q)); 64 memset(vis, false, sizeof(vis)); 65 for(int i = 1; i<=n; i++) 66 if(!vis[i]) 67 dfs(i, ++index); 68 69 sort(q+1,q+1+index); 70 int ans = (q[1].num-1)*q[1].num/2; 71 for(int i = 2; i<=index; i++) 72 { 73 ans += (q[i].num-1)*q[i].num/2; 74 if(!q[1].hav || !q[i].hav) 75 { 76 ans += q[1].num*q[i].num; 77 q[1].num += q[i].num; 78 q[1].hav = q[1].hav||q[i].hav; 79 } 80 } 81 82 ans -= m; 83 printf("%d\n", ans); 84 }