数据结构课设---网络流

昨天学了下最大流,今天早晨看了看费用流,
其中最大流经常用于求二分图最大匹配及最短路,费用流的题经常需要添加一个超级源点及超级汇点,人为设置流量及费用(流量一般为1,费用一般为最短路径)将原来的不知道什么题转化为费用流。

有上下界无源汇可行流问题

一般的,定义一个网络是一个加权的有向图G=(V, E, C), E中的每条弧(u, v)都有一个容量上界C(u, v)≥0。

如果人为的规定V中的两个点s和t,其中s没有入度而t没有出度;并为E中的每条弧(u, v)赋予一个值f(u,v)≥0, f满足以下两个条件:

①除s,t之外的任意点都满足: img
②任意一条 E中的弧(u, v),都满足f(u,v)≤c(u, v)
则称f是G的一个可行流,称s为流的源且t是流的汇。前一个条件被称为流量平衡条件,而后者则是容量限制条件。

而如果一个可行流f使原点提供的流量达到最大,则称f是G网络的最大流。

如果为G中的每条边再加入一个容量下界:令G=(V,E,B,C), B(u, v)表示弧(u, v)的容量下界。这样G就是一个容量有上下界的流网络。类似的定义G中的可行流f:
①除s,t之外的任意一个点 i都满足: img
②任意一条E中的弧(u,v)都满足B(u, v)≤f(u,v)≤C(u, v)。

在一个有上下界的流网络G中,不设源和汇,但要求任意一个点i都满足流量平衡条件。
且每条边满足容量限制的条件下,寻找一个可行流f,或指出这样的可行流不存在,这种问题为无源汇的可行流,此类题的图中有环,也被称作循环流;
仔细分析一下,由于普通最大流中对每条边中流量的约束条件仅仅是f(u,v)≥0,而在这个问题中,流量却必须大于等于某个下界。因此可以想到,设
f(u,v)= B(u,v)+g(u, v) (*)
其中g(u,v)≥0,这样就可以保证f≥B,同时为了满足上界限制,有g(u,v) ≤C(u,v)-B(u, v)。
令g(u,v)=C(u, v)- B(u,v)。则大致可以将g看作无上界流网络C中的一个可行流。(修改原图中每条边的流量下界为0,上界为原上界-原下界,视为该边现在已经拥有了等同于该边流量下界的基础流量了)

但这样直接转化显然是不对的,由于每条边在原图中的流量下界不同,导致他们现在的基础流量不同;于是如果再让现在图中每个点出入相等,则表面相等,实则不同;如图:

imgimgimg

红色边即为我们从原图中分离出的下界流量,黑色图是我们的新图,为了让新图也能满足流量平衡条件,要新建一个源点和一个汇点,设一点的红色边(流过该点的下界)总流量值为d(假设流出为正,流入为负)

如果d大于零,那么新图中该点流量要平衡还需流出大小为d的流量,那么建立该点到汇点流量为d的一条边,d小于零时相反,建立源点到该点流量为d的边

最后的图(图画的有的丑意思有就行。。)
img

算法:

  1. 按上述方法构造新网络(分离必要弧,附加源汇)
  2. 求附加源x到附加汇y的最大流
  3. 若x的出弧或y的入弧都满,则有解,将必要弧合并回原图;否则,无解。

若附加边满流,则跑出了一组可行流,原图中每条边的可行流是他在现在图中对应边的流量加流量下界

待解决:跑出的可行流有特性吗

CSP链接:http://118.190.20.162/view.page?gpid=T84

一个无源汇可行最小费用流问题,判断可行流的时候附加边费用视为0求出跑最小费用流即可

参考:https://wenku.baidu.com/view/0f3b691c59eef8c75fbfb35c.html

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll     base=233;
const int MAXN=1e5+10;
#define pi  acos(-1.0)
#define INF  0x3f3f3f3f
#define mod   1e9+7
#define lson rt<<1,l,mid
#define endll printf("\n")
#define pii pair<int, int>
#define rson rt*2+1,mid+1,r
#define s1(a) scanf("%d",&a)
#define stop system("pause")
#define lowbit(x)  ((x)&(-x))
#define s2(a,b) scanf("%d %d",&a,&b)
#define mem(a,b) memset(a,b,sizeof(a))
#define s3(a,b,c) scanf("%d %d %d",&a,&b,&c)
struct Graph
{
    int tot,head[MAXN];
    struct IN{int v,next,w,c;}edge[MAXN<<1];

    void init(){mem(head,-1);tot=0;}
    void addedge(int u,int v,int w,int c)
    {
        edge[tot].v=v;edge[tot].w=w;
        edge[tot].c=c;edge[tot].next=head[u];
        head[u]=tot++;
        //
        edge[tot].v=u;edge[tot].w=0;
        edge[tot].c=-c;edge[tot].next=head[v];
        head[v]=tot++;
    }
    int Start(int u){return head[u];}
    int To(int i){return edge[i].v;}
    int Val(int i){return edge[i].w;}
    int Cost(int i){return edge[i].c;}
    int Next(int i){return edge[i].next;}
    void Res(int i,int v){edge[i].w-=v;}
}G;
int n,m,e;//每边花费
int s,t;
int sum;//建立新图中源点的总流出值
int add;//建新图的时候删去的下界总流量
int du[MAXN];//某点向外流出的附加边总值与流进的附加边总权值之差
void input()
{
    s2(n,m);G.init();
    mem(du,0);add=0;
    for(int i=0;i<m;i++)
    {
        int u,v;char tt[2];
        scanf("%d%d%s",&u,&v,tt);
        char t=tt[0];
        if(t=='A')//A上界INF下界1,为了消除下界影响建立附加边u-->汇点-->源点-->v
        {
            du[u]--;du[v]++;//u点加上下界值(流出
            add+=e;//统计总的减去的下界流量值
            G.addedge(u,v,INF,e);//
        }
        else if(t=='B')//B上界1下界1
        {
            du[u]--;du[v]++;
            add+=e;//(0,0)的边不用建了
        }
        else if(t=='C')//下界0上界INF
            G.addedge(u,v,INF,e);
        else if(t=='D')//上界1下界1
            G.addedge(u,v,1,e);
    }
    //添加附加边
    s=0,t=n+1,sum=0;//用于判断是否满足源点满流
    for(int i=1;i<=n;i++)
    {
        if(du[i]>0)//需要添加流入的边
            sum+=du[i],G.addedge(s,i,du[i],0);
        else if(du[i]<0)
            G.addedge(i,t,-du[i],0);
    }
}
int flow[MAXN];//
int vis[MAXN],dis[MAXN];//用于SPFA
int pre[MAXN],rec[MAXN];//用于回溯
int SPFA(int s,int t)
{
    mem(vis,0);mem(dis,INF);
    queue<int>q;q.push(s);
    dis[s]=0;flow[s]=INF;
    while(!q.empty())
    {
        s=q.front();q.pop();vis[s]=0;
        for(int i=G.Start(s);~i;i=G.Next(i))
        {
            int v=G.To(i);
            if(G.Val(i)<=0) continue;//不存在增广路
            if(dis[v]>dis[s]+G.Cost(i))
            {
                dis[v]=dis[s]+G.Cost(i);
                pre[v]=s;rec[v]=i;
                flow[v] = min(flow[s],G.Val(i));
                if(!vis[v]) vis[v]=1,q.push(v);
            }
        }
    }
    if(dis[t]==INF) return -1;
    return flow[t];
}
int mcmf(int s,int t)
{
    int maxflow=0,mincost=0,minflow;
    while((minflow=SPFA(s,t))!=-1)
    {
        maxflow+=minflow;
        mincost+=dis[t]*minflow;
        for(int k=t;k!=s;k=pre[k])
            G.Res(rec[k],minflow),G.Res(rec[k]^1,-minflow);
    }
    if(maxflow!=sum) return -1;
    return mincost+add;
}
int main()
{
    int T,S;
    s3(T,S,e);
    while(T--)
    {
        input();
        printf("%d\n",mcmf(s,t));
    }
    //stop;
}

猜你喜欢

转载自www.cnblogs.com/Herlo/p/12131526.html