[题解]UVA11594 All Pairs Maximum Flow

UVA11594

很模板的最小割树

不会可以去这里

题目要求所有点对的最大流。我们可以直接上板子,建出最小割树后在树上倍增求出最小割就行了。

时间复杂度:\(O(T(n^3m+n^2logn))\),看起来完全过不了但是\(dinic\)的复杂度跑不满所以可以稳过。

代码:(很短的,确信)

#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>

using namespace std;

#define re register
#define il inline

const int N=210;
const int M=80010;
const int inf=0x3f3f3f3f;

namespace IO
{
char bufr[(1<<21)+100],bufw[(1<<21)+100],*p1=bufr,*p2=bufr,Tmp[100];
int p,p3=-1;
il char get_char(){return p1==p2&&(p2=(p1=bufr)+fread(bufr,1,1<<21,stdin))?EOF:*p1++;}
#define isdigit(ch) (ch>=48&&ch<=57)
template <typename T>
il void read(T &x)
{
	x=0;re char ch=get_char();
	while(!isdigit(ch)) ch=get_char();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=get_char();
}
template <typename T>
il void write(T x)
{
	if(x/10) write(x/10);
	putchar(x%10+48);
}
}
using namespace IO;
//IO优化

il void swap(int &a,int &b){a^=b^=a^=b;}
il int min(int a,int b){return a<b?a:b;}

int T,n;

namespace dinic
{
	int cnt=1,h[N];
	struct edge{int v,res,nxt;}e[M];
	il void add(int u,int v,int w){e[++cnt]=(edge){v,w,h[u]};h[u]=cnt;}
	int dep[N],cur[N];
	il bool bfs(int s,int t)
	{
		for(re int i=1;i<=n;++i)
			dep[i]=0,cur[i]=h[i];
		queue<int>q;q.push(s);dep[s]=1;
		while(!q.empty())
		{
			re int u=q.front();q.pop();
			for(re int i=h[u];i;i=e[i].nxt)
				if(!dep[e[i].v]&&e[i].res)
				{
					dep[e[i].v]=dep[u]+1;
					q.push(e[i].v);
				}
		}
		return dep[t];
	}
	il int dfs(int x,int flow,int t)
	{
		if(!flow||x==t) return flow;
		re int tmp=0,f;
		for(re int i=cur[x];i;i=e[i].nxt)
		{
			cur[x]=i;
			if(dep[e[i].v]>dep[x]&&(f=dfs(e[i].v,min(e[i].res,flow-tmp),t)))
			{
				tmp+=f;
				e[i].res-=f;
				e[i^1].res+=f;
				if(!(flow-tmp)) break;
			}
		}
		return tmp;
	}
	il int maxflow(int s,int t)
	{
		for(re int i=2;i<=cnt;i+=2)
			e[i].res+=e[i^1].res,e[i^1].res=0;
		re int ans=0;
		while(bfs(s,t)) ans+=dfs(s,inf,t);
		return ans;
	}
}
//封装dinic板子

namespace GHT
{
	int cnt,h[N],lg;
	struct edge{int v,w,nxt;}e[M];
	il void add(int u,int v,int w){e[++cnt]=(edge){v,w,h[u]};h[u]=cnt;}
	int node[N];
	int tmp1[N],tmp2[N];
	il void build(int l,int r)
	{
		if(l>=r) return;
		re int u=node[l],v=node[l+1];
		re int cut=dinic::maxflow(u,v);
		add(u,v,cut);add(v,u,cut);
		re int cnt1=0,cnt2=0;
		for(re int i=l;i<=r;++i)
		{
			if(dinic::dep[node[i]]) tmp1[++cnt1]=node[i];
			else tmp2[++cnt2]=node[i];
		}
		for(re int i=l;i<=l+cnt1-1;++i) node[i]=tmp1[i-l+1];
        for(re int i=l+cnt1;i<=r;++i) node[i]=tmp2[i-cnt1-l+1];
		build(l,l+cnt1-1);build(l+cnt1,r);
	}
    //建树
	int dep[N],fa[10][N],st[10][N];
	il void dfs(int x,int f)
	{
		dep[x]=dep[f]+1;
		for(re int i=1;i<=lg;++i)
		{
			fa[i][x]=fa[i-1][fa[i-1][x]];
			st[i][x]=min(st[i-1][x],st[i-1][fa[i-1][x]]);
		}
		for(re int i=h[x];i;i=e[i].nxt)
			if(e[i].v^f)
			{
				st[0][e[i].v]=e[i].w;
				fa[0][e[i].v]=x;
				dfs(e[i].v,x);
			}
	}
    //预处理倍增
	il int query(int u,int v)
	{
		re int res=inf;
		if(dep[u]<dep[v]) swap(u,v);
		for(re int i=lg;i>=0;--i)
			if(dep[fa[i][u]]>=dep[v])
				res=min(res,st[i][u]),u=fa[i][u];
		if(u==v) return res;
		for(re int i=lg;i>=0;--i)
			if(fa[i][u]^fa[i][v])
			{
				res=min(res,st[i][u]);
				res=min(res,st[i][v]);
				u=fa[i][u];v=fa[i][v];
			}
		res=min(res,st[0][u]);
		res=min(res,st[0][v]);
		return res;
	}
    //询问最小割
}
//封装最小割树板子

il void init()
{
	dinic::cnt=1;GHT::cnt=0;
	memset(dinic::h,0,sizeof(dinic::h));
	memset(GHT::h,0,sizeof(GHT::h));
	memset(GHT::st,0x3f,sizeof(GHT::st));
	for(re int i=1;i<=n;++i) GHT::node[i]=i;
}
//多测初始化

int main()
{
	read(T);
	for(re int Cas=1;Cas<=T;++Cas)
	{
		read(n);init();GHT::lg=log2(n);
		for(re int i=1;i<=n;++i)
			for(re int j=1,w;j<=n;++j)
			{
				read(w);
				if(!w) continue;
				dinic::add(i,j,w);
				dinic::add(j,i,0);
			}
		GHT::build(1,n);GHT::dfs(1,0);
		printf("Case #%d:\n",Cas);
		for(re int i=1;i<=n;++i)
			for(re int j=1;j<=n;++j)
			{
				write(i^j?GHT::query(i,j):0);
				putchar(j<n?' ':'\n');
			}
	}
	return 0;
}
posted @ 2020-12-04 16:29  watermonster1y1  阅读(60)  评论(1编辑  收藏  举报