zoukankan      html  css  js  c++  java
  • 网络流24题 Updating

    p.s:

    ① 此随笔着重讲的是建模思路,可能不会贴上代码。

    ② 以下出现的S都代表源点,T都代表汇点。

    1、飞行员配对问题

    飞行员配对问题

    Solution:

    二分图匹配模板。可以用匈牙利算法,也可用最大流。

    网络流的建模:

    由S向左部图连容量为1的边,右部图向T连容量为1的边,左右部图间根据给出的条件,对应连上一条容量为1的边。

    2、分配问题

    分配问题

    二分图带权匹配模板。可以用KM算法,也可以用费用流。

    费用流的建模:

    在二分图最大匹配建图的基础上,给左右部图间的连边赋上1的费用,其他边费用为0。

    3、试题库问题

    试题库问题

    二分图多重匹配模板。

    网络流的建模:

    在二分图最大匹配建图的基础上,只需要把T连向左部图(左部图为题中试题类型)的边容量改为需要的试题量。

    4、圆桌问题

    实际上可以说应该说是多重匹配问题。

    这个合适上一个题的区别就在于,上一题只有左部图可以连多条边,而此题左右部图都可以。

    所以建模的话,只需在上述基础上,右部图再往T连对应容量的边即可。

    5、负载平衡问题

    负载平衡问题

    Solution:

    这个题其实费用流才是真暴力。。。数学做法只要O(nlogn)。

    但是,既然是24题当然得用网络流知识做嘛。。

    这个建模没那么好想:

    首先,我们需要注意到,一个点它只可以与前面的点或后面的点进行交换,且要么补给别人,要么接受别人补给。

    对于这种只有出入两种情况的,一般启发着往拆点二分图上靠。

    那么,左部图的点向右部图的点连的边表示左部给右部补给。

    然后,可以把所有的点需要或多余的给计算出来。

    对于一个点,如果它有多余,那么从它对应的左节点 向 相邻的两节点的右节点 连容量为inf,费用为1的边。

    然后,S连向这些节点的左节点,容量为多余的量,费用为0。

    对于一个点,如果它需要别人补给,那么向T连一条容量为需要的量的边。

    但是还有一个很重要的点!!

    那就是,对于有多余的点,还需向相邻节点的左节点连一条连容量为inf,费用为1的边!!!

    这就相当于:这个点并不直接向两侧的点供应,而是把他们当做中转站而已。。

    Code↓:

    #include<bits/stdc++.h>
    #define RG register
    #define IL inline 
    using namespace std;
    
    const int N=110;
    const int inf=0x3f3f3f3f;
    
    queue<int> q;
    int n,S,T,cost,s[N],a[N],tot=1,pre[N<<2],vis[N<<2],dis[N<<2],head[N<<2],Minf[N<<2];
    
    struct EDGE{int next,to,v,w;}e[N*N];
    
    IL void make(int a,int b,int c,int d) {
        e[++tot]=(EDGE){head[a],b,c,d},head[a]=tot;
        e[++tot]=(EDGE){head[b],a,0,-d},head[b]=tot;
    }
    
    IL int spfa() {
        RG int i,x,y;
        while(!q.empty()) q.pop();
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));
        q.push(S),vis[S]=1,dis[S]=0,Minf[S]=inf;
        while(!q.empty()) {
            x=q.front(),vis[x]=0,q.pop();
            for(i=head[x];i;i=e[i].next) {
                if(e[i].v&&dis[y=e[i].to]>dis[x]+e[i].w) {
                    dis[y]=dis[x]+e[i].w;
                    pre[y]=i,Minf[y]=min(Minf[x],e[i].v);
                    if(!vis[y]) vis[y]=1,q.push(y);
                }
            }
        }
        return dis[T]!=inf;
    }
    
    IL void update() {
        RG int i,now=T;
        while(now!=S) {
            i=pre[now];
            e[i].v-=Minf[T],e[i^1].v+=Minf[T];
            now=e[i^1].to;
        }
        cost+=Minf[T]*dis[T];
    }
    
    int main()
    {
        RG int i,ave,sum=0;
        scanf("%d",&n);
        for(i=1;i<=n;++i) scanf("%d",&s[i]),sum+=s[i];
        for(i=1,ave=sum/n;i<=n;++i) s[i]-=ave;
        S=1,T=2*n+2;
        for(i=1;i<=n;++i) {
            if(s[i]>0) make(S,i+1,s[i],0);
            else make(i+n+1,T,-s[i],0);
        }
        for(i=1;i<=n;++i) {
            if(i!=1) make(i+1,i,inf,1),make(i+1,i+n,inf,1);
            if(i!=n) make(i+1,i+2,inf,1),make(i+1,i+2+n,inf,1);
        }
        make(2,n+1,inf,1),make(2,n*2+1,inf,1);
        make(n+1,2,inf,1),make(n+1,n+2,inf,1);
        while(spfa()) update();
        printf("%d
    ",cost);
        return 0;
    }
    
    

    6、软件补丁问题

    软件补丁问题

    Solution:

    最短路!!(雾)

    一个需要注意的地方是,每个补丁可以用无限次。。。

    又由于错误数很少,所以,可以直接状压一下表示当前错误状态,跑最短路即可

    贴一下判断部分Code↓:

    IL int judge(int x,int id) {
    	if((x&b1[id])!=b1[id]||(x&b2[id])) return -1;
    	x-=x&f1[id],x|=f2[id];
    	return x;
    }
    

    7、孤岛营救问题

    孤岛营救问题

    Solution:

    BFS!!(额额额)

    思考一下如果需要知道什么?

    拥有的钥匙情况!

    不知道怎么办,设出来就好了。

    钥匙数小于等于10,直接状压后BFS即可。

    8、魔术球问题

    魔术球问题

    Solution:

    首先需要知道一个结论:

    放的球数和柱子数成正相关
    

    所以本题可以直接贪心(>_<)

    但是网络流怎么样做呢??

    还是考虑我们如果知道了什么东西就好做点了。

    球数和柱子数是吧。

    既然不知道,不妨尝试枚举,枚举基于上结论。

    考虑新进来一个球。

    那么由上结论可知,只要能放,就不会加入柱子。

    怎样判断一个球能不能放才是重点,网络流。

    我们考虑枚举之前能够和他连边的数,连上一条容量为1的边,

    如果,我们在当前残量网络上能跑出一条为1的增广路,那么就可以放,否则加柱子。

    Zeny神犇:这个题可以完全转换成最小路径覆盖啊。
    
    I:呃呃。。。
    
    Zeny神犇:你太呆了,这个题就相当于是给定了路径数求最大点数啊。
    
    菜鸡在神犇面前,只适合sto orz    
    

    9、汽车加油行驶问题

    汽车加油行驶问题

    Solution:

    直接最短路就好了。

    我写的spfa,而且是直接再网格上跑的,懒。

    需要注意一下转移的时候,边权可能需要讨论一下。

    10、最小路径覆盖问题

    最小路径覆盖问题

    Solution:

    路径最少意味着什么?

    终点数最少。这又意味着什么?

    没有出度的点最少。这在一张左右两部分别表示点入度和出度的二分图上又意味这什么?

    左部表示出度,没出度的点最少,就是左部没被匹配的点最少,那么就是:

    总点数-最大匹配。

    所以直接最大流。

    11、太空飞行计划问题

    太空飞行计划问题

    Solution:

    最大权闭合子图模板。

    闭合子图:

    给定一个有向图,从中选择一些点组成一个点集V.对于V中任意一个点,其后续节点都仍然在V中.
    

    最大权闭合子图的话,就是给一些边权值,有正有负,求权值最大的闭合子图。

    给个结论:

        最大权 闭合子图=正权之和-最小割/最大流
    

    建模:

    S向正权点连权值的边,负权点向T连权值绝对值的边,正权点负权点间建inf的边

    可以发现,这个还是很好理解的:

    S与正权点间的边如果满流了,那么意味着这些费用都用来填补负权了,没有收益。

    否则,这个差值就代表着选这个点及其后继点的收益。

    负权点与T同样可以类似分析。

    思维还是很巧妙的。

    12、方格取数问题

    方格取数问题

    Solution:

    首先,需要反向认识到:取数最大总和=所有数总和-不取的数最小的和

    这应该联想到最小割,那么考虑怎么建图:

    我们发现一个点能够影响的有且仅有它周围四个点,那么考虑黑白染色

    假设对于每一个黑点,我们向它四周的几个点连边,容量为无限.

    同时S向黑点连边,容量为黑点点权

    对于白点,白点向T连边,容量为白点点权

    这个时候跑最小割(最大流)即可

    此时我们割掉的那些边必然是非无限边,所以割一条边可以代表着:不选对应的那个格子。

    24/12ing

  • 相关阅读:
    程序员的7中武器
    需要强化的知识
    微软中国联合小i推出MSN群Beta 不需任何插件
    XML Notepad 2006 v2.0
    Sandcastle August 2006 Community Technology Preview
    [推荐] TechNet 广播 SQL Server 2000完结篇
    《太空帝国 4》(Space Empires IV)以及 xxMod 英文版 中文版 TDM Mod 英文版 中文版
    IronPython 1.0 RC2 更新 1.0.60816
    Microsoft .NET Framework 3.0 RC1
    《Oracle Developer Suite 10g》(Oracle Developer Suite 10g)V10.1.2.0.2
  • 原文地址:https://www.cnblogs.com/Bhllx/p/10617855.html
Copyright © 2011-2022 走看看