zoukankan      html  css  js  c++  java
  • BZOJ4519[Cqoi2016]不同的最小割——最小割树+map

    题目描述

    学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成
    两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。对于带权图来说,将
    所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在
    关于s,t的割中容量最小的割。
    而对冲刺NOI竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了。我们可以把
    视野放宽,考虑有N个点的无向连通图中所有点对的最小割的容量,共能得到N(N−1)
    2个数值。
    这些数值中互不相同的有多少个呢?这似乎是个有趣的问题。

    输入

    输入文件第一行包含两个数N,M,表示点数和边数。接下来M行,每行三个数u,v,w,
    表示点u和点v(从1开始标号)之间有条边权值是w。
    1<=N<=850 1<=M<=8500 1<=W<=100000

    输出

     输出文件第一行为一个整数,表示个数。

    样例输入

    4 4
    1 2 3
    1 3 6
    2 4 5
    3 4 4

    样例输出

    3
     
    最小割树模板题,暴力枚举任意两个点在最小割树上求路径边权最小值,用$map$存一下权值即可。
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    #define pr pair<int,int>
    using namespace std;
    int head[900];
    int to[1800];
    int val[1800];
    int next[1800];
    int dep[900];
    int tot;
    int f[900][12];
    int g[900][12];
    int n,m,k;
    int u,v,w;
    int id[900];
    int now;
    map<int,int>mp;
    void add_edge(int u,int v,int w)
    {
    	next[++tot]=head[u];
    	head[u]=tot;
    	to[tot]=v;
    	val[tot]=w;
    }
    namespace DINIC
    {
    	int tot=1;
    	int S,T;
    	int q[900];
    	int d[900];
    	int head[900];
    	int next[18000];
    	int val[18000];
    	int col[900];
    	int to[18000];
    	int vir[18000];
    	void add(int u,int v,int w)
    	{
    		next[++tot]=head[u];
    		head[u]=tot;
    		to[tot]=v;
    		val[tot]=w;
    		vir[tot]=w;
    	}
    	bool bfs(int S,int T)
    	{
    		int l=0,r=0;
    		memset(d,-1,sizeof(d));
    		q[r++]=S;
    		d[S]=0;
    		while(l<r)
    		{
    			int now=q[l];
    			l++;
    			for(int i=head[now];i;i=next[i])
    			{
    				if(d[to[i]]==-1&&val[i])
    				{
    					d[to[i]]=d[now]+1;
    					q[r++]=to[i];
    				}
    			}
    		}
    		if(d[T]==-1)
    		{
    			return false;
    		}
    		else
    		{
    			return true;
    		}
    	}
    	int dfs(int x,int maxflow)
    	{
    		if(x==T)
    		{
    			return maxflow;
    		}
    		int nowflow;
    		int used=0;
    		for(int i=head[x];i;i=next[i])
    		{
    			if(d[to[i]]==d[x]+1&&val[i])
    			{
    				nowflow=dfs(to[i],min(maxflow-used,val[i]));
    				val[i]-=nowflow;
    				val[i^1]+=nowflow;
    				used+=nowflow;
    				if(nowflow==maxflow)
    				{
    					return maxflow;
    				}
    			}
    		}
    		if(used==0)
    		{
    			d[x]=-1;
    		}
    		return used;
    	}
    	int dinic()
    	{
    		for(int i=2;i<=tot;i++)
    		{
    			val[i]=vir[i];
    		}
    		int res=0;
    		while(bfs(S,T)==true)
    		{
    			res+=dfs(S,0x3f3f3f3f);
    		}
    		return res;
    	}
    	void find(int x)
    	{
    		col[x]=now;
    		for(int i=head[x];i;i=next[i])
    		{
    			if(col[to[i]]!=now&&val[i])
    			{
    				find(to[i]);
    			}
    		}
    	}
    	void build(int l,int r)
    	{
    		if(l>=r)
    		{
    			return ;
    		}
    		S=id[l],T=id[l+1];
    		int cut=dinic();
    		now++;
    		find(S);
    		int L=l,R=r;
    		for(int i=l;i<=r;i++)
    		{
    			if(col[id[i]]==now)
    			{
    				q[L++]=id[i];
    			}
    			else
    			{
    				q[R--]=id[i];
    			}
    		}
    		for(int i=l;i<=r;i++)
    		{
    			id[i]=q[i];
    		}
    		add_edge(S,T,cut);
    		add_edge(T,S,cut);
    		build(l,L-1);
    		build(R+1,r);
    	}
    };
    void dfs(int x)
    {
    	for(int i=1;i<=10;i++)
    	{
    		f[x][i]=f[f[x][i-1]][i-1];
    		g[x][i]=min(g[x][i-1],g[f[x][i-1]][i-1]);
    	}
    	for(int i=head[x];i;i=next[i])
    	{
    		if(to[i]!=f[x][0])
    		{
    			dep[to[i]]=dep[x]+1;
    			f[to[i]][0]=x;
    			g[to[i]][0]=val[i];
    			dfs(to[i]);
    		}
    	}
    }
    int lca(int x,int y)
    {
    	int res=1<<30;
    	if(dep[x]<dep[y])
    	{
    		swap(x,y);
    	}
    	int d=dep[x]-dep[y];
    	for(int i=0;i<=10;i++)
    	{
    		if(d&(1<<i))
    		{
    			res=min(res,g[x][i]);
    			x=f[x][i];
    		}
    	}
    	if(x==y)
    	{
    		return res;
    	}
    	for(int i=10;i>=0;i--)
    	{
    		if(f[x][i]!=f[y][i])
    		{
    			res=min(res,g[x][i]);
    			res=min(res,g[y][i]);
    			x=f[x][i];
    			y=f[y][i];
    		}
    	}
    	res=min(min(g[x][0],g[y][0]),res);
    	return res;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&u,&v,&w);
    		DINIC::add(u,v,w);
    		DINIC::add(v,u,w);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		id[i]=i;
    	}
    	DINIC::build(1,n);
    	dfs(1);
    	int ans=0;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=i+1;j<=n;j++)
    		{
    			if(!mp[lca(i,j)])
    			{
    				mp[lca(i,j)]=1;
    				ans++;
    			}
    		}
    	}
    	printf("%d",ans);
    }
  • 相关阅读:
    typedef的用法
    重定向在网络编程中的理解
    简答的理解C语言中的各种类型函数
    栈、堆、静态存储区
    标识符起作用范围----作用域、连接类型、存储期
    main函数的argc和argv
    基本数据类型
    数组与指针
    第一章 CLR的执行模型
    Revit 二次开发 沿弧形路径创建拉伸屋顶
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10449711.html
Copyright © 2011-2022 走看看