BZOJ 4435 [双连通分量][Hash]

来源:互联网 发布:知乎客户端电脑版下载 编辑:程序博客网 时间:2024/05/17 09:20

Description

你被雇佣升级一个旧果汁加工厂的橙汁运输系统。系统有管道和节点构成。每条管道都是双向的,且每条管道的流量都是1升每秒。管道可能连接节点,每个节点最多可以连接3条管道。节点的流量是无限的。节点用整数1n来表示。在升级系统之前,你需要对现有系统进行分析。对于两个不同节点stst的流量被定义为:当s为源点,t为汇点,从s能流向t的最大流量。以下面的第一组样例数据为例,16的流量为312的流量为2。计算每一对满足a<b的节点ab的流量的和。

Solution

根据最大流最小割定理,我们要求的其实就是最小割。题中所说每个节点只会连出至多三条边,显然最小割至多为3。分类讨论一下:
若最小割为0:说明两点之间不连通。
若最小割为1:说明两点处于不同的双连通分量中。
若最小割为23:考虑从图中删去一条边,若删去任何一条边之后两个点仍在同一双连通分量中,则说明最小割为3否则为2
如何判断删去任意一条边之后的双连通分量编号是否相同,只需要对每个点Hash一下。(注意要是有序的Hash)。
时间复杂度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;}
原创粉丝点击