zoukankan      html  css  js  c++  java
  • 网络流总结

    网络流总结

    两个板子

    【模板】最大流

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define inf 1000000000
    const int _ = 100005;
    struct edge{int to,next,w;}a[_<<1];
    int n,m,s,t,head[_],cnt=1,cur[_],dep[_],ans;
    queue<int>Q;
    int gi()
    {a
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    void link(int u,int v,int w)
    {
    	a[++cnt]=(edge){v,head[u],w};
    	head[u]=cnt;
    	a[++cnt]=(edge){u,head[v],w};
    	head[v]=cnt; 
    }
    int bfs()
    {
    	memset(dep,0,sizeof(dep));
    	Q.push(s);dep[s]=1;
    	while (!Q.empty())
    	{
    		int u=Q.front();Q.pop();
    		for (int e=head[u];e;e=a[e].next)
    			if (!dep[a[e].to]&&a[e].w)
    				dep[a[e].to]=dep[u]+1,Q.push(a[e].to);
    	}
    	return dep[t];
    }
    int dfs(int u,int flow)
    {
    	if (u==t)
    		return flow;
    	for (int &e=cur[u];e;e=a[e].next)
    		if (dep[a[e].to]==dep[u]+1&&a[e].w)
    		{
    			int temp=dfs(a[e].to,min(a[e].w,flow));
    			if (temp) {a[e].w-=temp;a[e^1].w+=temp;return temp;}
    		}
    	return 0;
    }
    int main()
    {
    	n=gi();m=gi();
    	/*
    	    中间是建边的过程
    	*/
    	while (bfs())
    	{
    		for (int i=1;i<=n;i++) cur[i]=head[i];
    		while (int temp=dfs(s,inf)) ans+=temp;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    【模板】最小费用最大流

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define inf 1000000000
    const int _ = 100005;
    struct edge{int to,next,w,cost;}a[_<<1];
    int n,m,s,t,head[_],cnt=1,dis[_],vis[_],pe[_],ans;
    queue<int>Q;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    void link(int u,int v,int w,int cost)
    {
    	a[++cnt]=(edge){v,head[u],w,cost};
    	head[u]=cnt;
    	a[++cnt]=(edge){u,head[v],0,-cost};
    	head[v]=cnt;
    }
    bool spfa()
    {
    	memset(dis,63,sizeof(dis));
    	dis[s]=0;Q.push(s);
    	while (!Q.empty())
    	{
    		int u=Q.front();Q.pop();
    		for (int e=head[u];e;e=a[e].next)
    		{
    			int v=a[e].to;
    			if (a[e].w&&dis[v]>dis[u]+a[e].cost)
    			{
    				dis[v]=dis[u]+a[e].cost;pe[v]=e;
    				if (!vis[v]) vis[v]=1,Q.push(v);
    			}
    		}
    		vis[u]=0;
    	}
    	if (dis[t]<dis[0]) return false;
            int sum=inf;
    	for (int i=t;i!=s;i=a[pe[i]^1].to)
    		sum=min(sum,a[pe[i]].w);
    	ans+=sum*dis[t];
    	for (int i=t;i!=s;i=a[pe[i]^1].to)
    		a[pe[i]].w-=sum,a[pe[i]^1].w+=sum;
    }
    int main()
    {
    	n=gi();m=gi();
    	/*
    	    中间是建边的过程
    	*/
    	while (spfa()) ;
    	printf("%d
    ",ans);
    	return 0;
    }
    

    技巧总结

    单点限流量

    拆点,每个点拆成出点和入点,连边的时候从出点连向入点。

    连续转移问题

    也就是说状态会持续转移,从一个点到一个点再到另一个点。经典例题https://www.luogu.org/problemnew/show/1251餐巾计划问题(网络流24题10)
    我们换个方式理解,因为每个点通过的流量是限制了的,所以可以认为每个点都是源点,也都是汇点。拆成两个点,s向每个“源点”连一条容量为指定数量的边,每个“汇点”向t同样连一条容量为指定数量的边,然后就是最小费用流了。

    最大收益问题

    最大收益不好转化为最大流,但转化为最小割又出现了矛盾。这里转化一下思想,其实求最大收益,就是求最小损失。我们先假设所有能赚到的收益都赚到了,然后就是最小化自己的损失。
    同样以一道题来讲。https://www.luogu.org/problemnew/show/P2762太空飞行计划问题(网络流24题2)
    我们要选择一些实验并购买一些实验所需仪器,使总利润最大。如果不转化模型的话,既赚钱又花钱就很难处理。我们先假设我们已经拿到了所有的实验利润,通过最小割问题求解。

    最小费用流,要求费用最小的同时经过的边最少

    费用全部乘一个大于边数的数字,然后每条边费用加1

    最小费用流判断某一条边是否无论在哪种最优策略中都会被选到

    在残余网络上跑spfa,若一条边的前后两个点的dis的差值不是边权,就说明上述条件成立。

  • 相关阅读:
    ADO.Net——增、删、改、查
    面向对象——类库五大原则
    面向对象——设计模式和委托
    JS 函数 内置方法和对象
    js 字符串、数组类型 及方法
    复习一下 Python三元运算
    复习一下 列表
    前端 2 CSS 选择器
    前端 1 HTML
    39
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8137534.html
Copyright © 2011-2022 走看看