hdu 4635(强连通分量)

来源:互联网 发布:三星ml2161清零软件 编辑:程序博客网 时间:2024/04/24 17:05

题目链接

不难得到如下结论:如果原图不是强连通, 那么最优解肯定是只剩两个强连通分量且每个分量内都为完全图, 可以列出数学表达式不难

发现最后的结果只和两个分量中的点数的乘积有关, 由于两者的和一定使两者的差尽可能大, 但一个点如果既有出度又有入度就不能单

独将它作为最后的一个点, 所以我要考虑只有出度或者入度的点。


#include <iostream>#include <stack>#include <queue>#include <cstdio>#include <cstring>#include <algorithm>#include <cstdlib>#include <vector>#include <cmath>using namespace std;typedef long long LL;const int N = 100005;const int M = N << 4;struct SCC {struct Edge {int v;Edge* next;void init(int a, Edge* e) {v = a, next = e;}};Edge E[M], * head[N];int low[N], pre[N], no[N];int cnt[N];int n, tot, sum, tdfn, m;int in[N], out[N];stack<int> stk;void init(int n, int m) {this->n = n;this->m = m;for (int i = 0; i < n; i++) {head[i] = 0;no[i] = -1;pre[i] = 0;cnt[i] = 0;}tot = 0, sum = 0, tdfn = 0;}void add(int u, int v) {E[tot].init(v, head[u]);head[u] = &E[tot++];}void dfs(int u) {pre[u] = low[u] = ++tdfn;stk.push(u);for (Edge* e = head[u]; e; e = e->next) {int v =e->v;if (!pre[v]) {dfs(v);low[u] = min(low[u], low[v]);}else if (no[v] == -1)low[u] = min(low[u], pre[v]);}if (low[u] == pre[u]) {sum++;while(1) {int x = stk.top();stk.pop();no[x] = sum - 1;if (x == u) break;}}}LL run() {for (int i = 0; i < n; i++)if (pre[i] == 0)dfs(i);if (sum == 1) return -1;int key = N;for (int i = 0; i < n; i++) {cnt[no[i]]++;}for (int i = 0; i < sum; i++)in[i] = 0, out[i] = 0;for (int i = 0; i < n; i++)for (Edge* e = head[i]; e; e = e->next) {int v = e->v;if (no[i] == no[v]) continue;in[no[v]]++;out[no[i]]++;}for (int i = 0; i < sum; i++) {if (in[i] && out[i]) continue;key = min(key, cnt[i]);}LL res = (LL) n * n - n - m - (LL)key * (n - key);return res;}}G;int main() {int test, u, v, n, m;scanf("%d", &test);int cas = 1;while (test--) {scanf("%d%d", &n, &m);G.init(n, m);for (int i = 0; i < m; i++) {scanf("%d%d", &u, &v);u--, v--;G.add(u, v);}cout << "Case " << cas++ << ": " << G.run() << endl;}return 0;}

原创粉丝点击