zoukankan      html  css  js  c++  java
  • [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;
    }
    

     小结:好东西啊。

  • 相关阅读:
    Nosql介绍
    linux系统安装mysql
    linux下装tomcat教程
    linux系统下安装jdk教程
    XML解析
    XML 可扩展标记语言
    Oracle——子查询
    数据库——Oracle(增删改查,单行函数,多行函数,多表查询)
    Ubuntu16.04Scrapy爬虫定时任务
    大数据——zookeeper分布式集群管理工具的学习与使用
  • 原文地址:https://www.cnblogs.com/ShuraK/p/10244898.html
Copyright © 2011-2022 走看看