Description
你被雇佣升级一个旧果汁加工厂的橙汁运输系统。系统有管道和节点构成。每条管道都是双向的,且每条管道的流量都是1升每秒。管道可能连接节点,每个节点最多可以连接3条管道。节点的流量是无限的。节点用整数1到n来表示。在升级系统之前,你需要对现有系统进行分析。对于两个不同节点s和t,s-t的流量被定义为:当s为源点,t为汇点,从s能流向t的最大流量。以下面的第一组样例数据为例,1-6的流量为3,1-2的流量为2。计算每一对满足a< b的节点a-b的流量的和。
Input
第一行包括2个整数n和m(2<=n<=3000,0<=m<=4500)——节点数和管道数。
接下来m行,每行包括两个相异整数a,b(1<=a,b<=n),表示一条管道连接节点a,b。
每个节点最多连接3条管道,每对节点最多被一条管道连接。
Output
输出一个整数——每对满足a< b的节点a-b的流量之和。
Sample Input
6 8
1 3
2 3
4 1
5 6
2 6
5 1
6 4
5 3
Sample Output
36
HINT
Source
考虑割流转化,然后做最小割树,最后把流量Hash出来统计
Claris说此题卡ISAP和Dinic常数,要用EK才行..
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 3010
#define GET (ch>='0'&&ch<='9')
using namespace std;
int n,m,top,ans,S,T,ret;
int num[MAXN],tmp[MAXN],q[MAXN],h[MAXN];
unsigned hash[4][MAXN],Pow=1;
struct edge { int st,to,c,id; edge *next,*rev; }e[MAXN<<2],*prev[MAXN];
inline void insert(int u,int v,int c) { e[++top].to=v;e[top].st=u;e[top].next=prev[u];prev[u]=&e[top];e[top].c=c;e[top].id=top; }
inline void add(int u,int v,int c) { insert(u,v,c);insert(v,u,c);prev[u]->rev=prev[v];prev[v]->rev=prev[u]; }
inline void in(int &x)
{
char ch=getchar();x=0;
while (!GET) ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();
}
bool bfs()
{
int l=0,r=1;memset(h+1,-1,sizeof(int)*n);h[q[0]=S]=0;
while (l<r) for (edge *i=prev[q[l++]];i;i=i->next) if (h[i->to]<0&&i->c) q[r++]=i->to,h[i->to]=i->id;
return h[T]!=-1;
}
void solve(int l,int r)
{
if (l>=r) return;
for (int i=1;i<=top;i+=2) e[i].c=e[i].rev->c=1;
S=num[r];T=num[l];ret=0;int j;
while (bfs())
{
ret++;
for (int i=T;i!=S;i=e[j].st) e[j=h[i]].c--,e[j].rev->c++;
}
Pow*=233;
for (int i=1;i<=n;i++) if (~h[i]) hash[ret][i]+=Pow;
int L=l,R=r;
for (int i=l;i<=r;i++) if (h[num[i]]<0) tmp[L++]=num[i]; else tmp[R--]=num[i];
memcpy(num+l,tmp+l,sizeof(int)*(r-l+1));solve(l,R);solve(L,r);
}
int main()
{
in(n);in(m);int u,v;
for (int i=1;i<=m;i++) in(u),in(v),add(u,v,1);
for (int i=1;i<=n;i++) num[i]=i;
solve(1,n);
for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) for (int k=0;k<4;k++)
if (hash[k][i]!=hash[k][j]) { ans+=k;break; }
cout<<ans<<endl;
}