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 */
时间: 2024-10-01 02:29:32