强连通分量
我们利用强连通分量进行缩点。然后找入度为0或者出度为0的点。
他们其中一个一定是在我们最终的图中被孤立的点。
为什么要这样说呢?
因为你仔细想想啊。假如我没有边,我让你用最多的边连出一个不是强连通分量的图
你是不是孤立一个点,使他只有出度没有入度或者只有入度没有出度?
那,这里不也是一样的吗?!其实,顺着感觉走就可以了。
然后我们统计就可以了。我们想对于一个出度为零或者入度为零的点,孤立他得到的最大收益应该为:
n(n-1)-m-cnt[i](n-cnt[i]) cnt[i]指该连通块中的点的数量。
这里用的是割补法求的,刚开始我想直接求,麻烦得很。。。。。。。。
我们注意到,这个式子里面只有一个变量cnt[i]
设为x把他单独出出来看:x^2-n*x 对称轴为n/2
我们可以直接根据这个式子判断,但是其实我们直接取最小值就好了。
因为有一个点数为k的连通块那么就必定会有一个点数为n-k的连通块。而二者是相等的!
不细心,wa了好多发:(
代码如下:
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
typedef long long ll;
const int max_m = 2e5 + 100;
const int max_n = 1e5 + 100;
struct edge{
int to, next;
}E[max_m];
int head[max_n];
int cnt = 1;
void add(int from, int to) {
E[cnt].to = to;
E[cnt].next = head[from];
head[from] = cnt++;
}
int cct[max_n];
stack<int> st;int tot = 0;
int dfn[max_n], low[max_n];
int col[max_n];int color = 0;
void tarjan(int u) {
dfn[u] = low[u] = ++tot;
st.push(u);
for (int i = head[u];i;i = E[i].next) {
int v = E[i].to;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (col[v] == 0)low[u] = min(low[u], dfn[v]);
}if (low[u] != dfn[u])return;
++color;
while (st.top() != u) {
col[st.top()] = color;
st.pop();
++cct[color];
}col[st.top()] = color;
st.pop();++cct[color];
}
int in[max_n], out[max_n];
int N, M;
int main() {
int T;scanf("%d", &T);
for (int tcase = 1;tcase <= T;++tcase) {
scanf("%d %d", &N, &M);
fill(head, head + N + 10, 0);cnt = 1;
fill(dfn, dfn + N + 10, 0);
fill(col, col + N + 10, 0);
fill(cct, cct + N + 10, 0);
fill(in, in + N + 10, 0);
fill(out, out + N + 10, 0);
color = tot = 0;
for (int i = 1, u, v;i <= M;++i) {
scanf("%d %d", &u, &v);
add(u, v);
}for (int i = 1;i <= N;++i)
if (!dfn[i])
tarjan(i);
if (color == 1) {
printf("Case %d: -1\n", tcase);
continue;
}for (int u = 1;u <= N;++u) {
for (int i = head[u];i;i = E[i].next) {
int v = E[i].to;
if (col[v] == col[u])continue;
++in[col[v]];++out[col[u]];
}
}
ll ans = 0;ll tmp = N;
for (int i = 1;i <= color;++i)
if (in[i] == 0 || out[i] == 0)
tmp = min(tmp, (ll)cct[i]);
ans = (ll)N * ((ll)N - 1) - ((ll)N - tmp) * tmp - M;
printf("Case %d: %lld\n", tcase, ans);
}
}
京公网安备 11010502036488号