• [bzoj2229][Zjoi2011]最小割_网络流_最小割树


    最小割 bzoj-2229 Zjoi-2011

    题目大意:题目链接

    注释:略。


    想法:

    在这里给出最小割树的定义。

    最小割树啊,就是这样一棵树。一个图的最小割树满足这棵树上任意两点之间的最小值就是原图中这两点之间的最小割。

    这个性质显然是非常优秀的。

    我们不妨这样假设,我么已经把最小割树求出来了,那么这个题就迎刃而解了。

    我们可以直接枚举点对,然后暴力验证就可以直接枚举出所有的合法点对是吧。

    那么问题来了,我们如何才能求出所有的合法的点对?

    这就需要用到了最小割树的构建过程。

    我们最小割树的构建方式是分治构建的。

    也就是说:

    我们每次直接随意取出两个点然后在原图中求出这两个点的最小割。

    并且在这两个点之间连一条等于最小割大小的边。

    之后我们对于原图把所有和S相连的分到一侧,把所有和T相连的分到另一侧。

    递归分治即可。

    Code:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define inf 0x3f3f3f3f
    #define N 155
    using namespace std;
    
    int cnt,n,m,dis[N],last[N],a[N],tmp[N],ans[N][N],s,t,mark[N];
    struct edge{int to,c,next;}e[N*200];
    queue <int> q;
    
    void addedge(int u,int v,int c)
    {
    	e[++cnt].to=v;e[cnt].c=c;e[cnt].next=last[u];last[u]=cnt;
    	e[++cnt].to=u;e[cnt].c=c;e[cnt].next=last[v];last[v]=cnt;
    }
    
    bool bfs()
    {
    	memset(dis,0,sizeof(dis));
    	dis[s]=2;
    	while (!q.empty()) q.pop();
    	q.push(s);
    	while (!q.empty())
    	{
    		int u=q.front();
    		q.pop();
    		for (int i=last[u];i;i=e[i].next)
    			if (e[i].c&&!dis[e[i].to])
    			{
    				dis[e[i].to]=dis[u]+1;
    				if (e[i].to==t) return 1;
    				q.push(e[i].to);
    			}
    	}
    	return 0;
    }
    
    int dfs(int x,int maxf)
    {
    	if (x==t||!maxf) return maxf;
    	int ret=0;
    	for (int i=last[x];i;i=e[i].next)
    		if (e[i].c&&dis[e[i].to]==dis[x]+1)
    		{
    			int f=dfs(e[i].to,min(e[i].c,maxf-ret));
    			e[i].c-=f;
    			e[i^1].c+=f;
    			ret+=f;
    			if (ret==maxf) break;
    		}
    	if (!ret) dis[x]=0;
    	return ret;
    }
    void dfs(int x)
    {
    	mark[x]=1;
    	for (int i=last[x];i;i=e[i].next)
    		if (e[i].c&&!mark[e[i].to]) dfs(e[i].to);
    }
    void solve(int l,int r)
    {
    	if (l==r) return;
    	s=a[l];t=a[r];
    	for (int i=2;i<=cnt;i+=2)
    		e[i].c=e[i^1].c=(e[i].c+e[i^1].c)/2;
    	int flow=0;
    	while (bfs()) flow+=dfs(s,inf);
    	memset(mark,0,sizeof(mark));
    	dfs(s);
    	for (int i=1;i<=n;i++)
    		if (mark[i])
    			for (int j=1;j<=n;j++)
    				if (!mark[j])
    					ans[i][j]=ans[j][i]=min(ans[i][j],flow);
    	int i=l,j=r;
    	for (int k=l;k<=r;k++)
    		if (mark[a[k]]) tmp[i++]=a[k];
    		else tmp[j--]=a[k];
    	for (int k=l;k<=r;k++)
    		a[k]=tmp[k];
    	solve(l,i-1);
    	solve(j+1,r);
    }
    
    int main()
    {
    	int cas;
    	scanf("%d",&cas);
    	while (cas--)
    	{
    		scanf("%d%d",&n,&m);
    		cnt=1;
    		for (int i=1;i<=n;i++)
    			a[i]=i;
    		memset(last,0,sizeof(last));
    		memset(ans,inf,sizeof(ans));
    		for (int i=1;i<=m;i++)
    		{
    			int x,y,z;
    			scanf("%d%d%d",&x,&y,&z);
    			addedge(x,y,z);
    		}
    		solve(1,n);
    		int q;
    		scanf("%d",&q);
    		for (int i=1;i<=q;i++)
    		{
    			int x,tot=0;
    			scanf("%d",&x);
    			for (int i=1;i<n;i++)
    				for (int j=i+1;j<=n;j++)
    					if (ans[i][j]<=x) tot++;
    			printf("%d
    ",tot);
    		}
    		cout<<endl;
    	}
    	return 0;
    }
    

     小结:好东西啊。

  • 相关阅读:
    MySQL之自增长
    MySQL字符集和校对规则
    关于MySQL安装目录bin下工具的详解
    Linux下载安装配置FTP
    Linux和Windows平台安装MySQL的两种方式
    kali安装linux-header
    Mysql之事务
    Linux之ps命令
    Linux之dd命令
    python爬虫之xpath的基本使用
  • 原文地址:https://www.cnblogs.com/ShuraK/p/10244898.html
Copyright © 2020-2023  润新知