Description
你被雇佣升级一个旧果汁加工厂的橙汁运输系统。系统有管道和节点构成。每条管道都是双向的,且每条管道的流量都是
1
升每秒。管道可能连接节点,每个节点最多可以连接
Solution
根据最大流最小割定理,我们要求的其实就是最小割。题中所说每个节点只会连出至多三条边,显然最小割至多为
3
。分类讨论一下:
若最小割为
若最小割为
1
:说明两点处于不同的双连通分量中。
若最小割为
如何判断删去任意一条边之后的双连通分量编号是否相同,只需要对每个点
时间复杂度
O(n2)
。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
inline void read(int &x) {
static char c; x = 0;
for (c = get(); c < '0' || c > '9'; c = get());
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
const int N = 3030;
const int M = 4545;
const int P = 2333333;
typedef long long ll;
struct edge {
int to, next;
edge (int t = 0, int n = 0):to(t), next(n) {}
};
edge G[M << 1];
int pre[N], low[N], bcc[N], sta[N];
int has[N], mark[M << 1], id[N];
int head[N];
int ans[N][N];
int n, m, x, y, Gcnt, clc, top, Bcnt, cnt, Ans;
inline int Min(int a, int b) {
return a < b ? a : b;
}
inline void AddEdge(int from, int to) {
G[++Gcnt] = edge(to, head[from]); head[from] = Gcnt;
G[++Gcnt] = edge(from, head[to]); head[to] = Gcnt;
}
void dfs(int u, int fa) {
low[u] = pre[u] = ++clc;
int to; id[u] = cnt;
sta[++top] = u;
for (int i = head[u]; i; i = G[i].next)
if (!mark[i]) {
to = G[i].to;
if (pre[to]) {
if (to != fa) low[u] = Min(low[u], low[to]);
} else if (to != fa) {
dfs(to, u); low[u] = Min(low[u], low[to]);
}
}
if (low[u] == pre[u]) {
Bcnt++;
while (sta[top] != u) {
bcc[sta[top]] = Bcnt;
top--;
}
bcc[sta[top--]] = Bcnt;
}
}
void SetBcc(int flag = 0) {
Bcnt = cnt = clc = top = 0;
memset(pre, 0, sizeof pre);
memset(id, 0, sizeof id);
for (int i = 1; i <= n; i++)
if (!pre[i]) {
cnt++; dfs(i, 0);
}
if (flag) return (void)("%%%%gjghfd%%%%");
for (int i = 1; i <= n; i++)
has[i] = ((ll)has[i] * M % P + bcc[i]) % P;
}
int main(void) {
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
read(n); read(m);
for (int i = 1; i <= m; i++) {
read(x); read(y);
AddEdge(x, y);
}
SetBcc(1);
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++) {
if (bcc[i] != bcc[j]) ans[i][j] = 1;
if (id[i] != id[j]) ans[i][j] = -1;
}
for (int i = 1; i <= Gcnt; i += 2) {
mark[i] = mark[i + 1] = 1;
SetBcc();
mark[i] = mark[i + 1] = 0;
}
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++) {
if (ans[i][j] != 0) continue;
if (has[i] == has[j]) ans[i][j] = 3;
else ans[i][j] = 2;
}
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
if (ans[i][j] > 0) Ans += ans[i][j];
cout << Ans << endl;
return 0;
}