最小费用最大流

来源:互联网 发布:蘑菇街秒杀软件 编辑:程序博客网 时间:2024/06/05 10:15

上周末打了两场网络赛,对于网络流的应用有了更深的体会【简单来讲就是还不懂得怎么自己写,就只是好像懂了一丢丢要怎么用】。把kuangbin大佬的模板再手敲一遍加上自己的注释。

//最小费用最大流

#include<cstdio>#include<cstring>#include<queue>#include<algorithm>#include<set>#include<map>using namespace std;const int maxn = 1e4;const int maxm = 1e5;const int inf = 0x3f3f3f3f;struct Edge{    int to,next,cap,flow,cost;}edge[maxm];int head[maxn],tol;int pre[maxn],dis[maxn];bool vis[maxn];int N; //节点个数,编号0->N-1 !全局变量 需要init赋值或主函数改变void init(int n){    N=n;    tol = 0;    memset(head,-1,sizeof(head));}void addedge(int u,int v,int cap,int cost) //边起点,终点,流量,费用{    edge[tol].to = v;    edge[tol].cap = cap;    edge[tol].cost = cost;    edge[tol].flow = 0;    edge[tol].next = head[u];    head[u] = tol++;    edge[tol].to = u;    edge[tol].cap = 0;    edge[tol].cost = -cost;    edge[tol].flow = 0;    edge[tol].next = head[v];    head[v] = tol++;}bool spfa(int s,int t)     //单源最短路径算法 可判断负环{    queue<int >q;    for(int i=0;i<N;i++)    {        dis[i] = inf;        vis[i] = false;        pre[i] = -1;    }    dis[s] = 0;    vis[s] = true;    q.push(s);    while(!q.empty())    {        int u = q.front();        q.pop();        vis[u] = false;        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v= edge[i].to;            if(edge[i].cap>edge[i].flow && dis[v]>dis[u]+edge[i].cost)            {                dis[v] = dis[u] + edge[i].cost;                pre[v] = i;                if(!vis[v])                {                    vis[v] = true;                    q.push(v);                }            }        }    }    if(pre[t]==-1) return false;    else return true;}int MCMF(int s,int t,int &cost)  //MinCostMaxFlow  返回最大流,cost存最小费用{    int flow = 0;    cost = 0;    while(spfa(s,t))    {        int Min = inf;        for(int i= pre[t];i!=-1;i=pre[edge[i^1].to])        {            if(Min>edge[i].cap-edge[i].flow)                Min=edge[i].cap-edge[i].flow;        }        for(int i= pre[t];i!=-1;i=pre[edge[i^1].to)        {            edge[i].flow += Min;            edge[i^1].flow -=Min;            cost += edge[i].cost*Min;        }        flow += Min;    }    return flow;}
最小费用最大流属于网络流的一种基本算法,上周末的应用中,一道是滑雪求最长路径(滑雪只能从高到低,所以是有向路),一道是在n个城市中辗转买、卖书的问题(中间没有多次买卖,choose two cities to buy and sell)。两道题的共同特点是n个点相互之间有路,不管是不是有向的,然后我们要找到最符合要求的一种方式。两道题中我们都可以额外添加两个点作为入点和汇点,用流量来限制通过每条路、每个点的次数,用费用来体现两点之间的【贡献】。在滑雪的问题中,因为题目中要求每个点只能经过一次(流量限制的是每条路经过的次数),所以我们可以把每个点拆成两个点所连通的路,并且把这条路的流量设置为1。两道题中,所求的其实是最大费用最大流的问题(滑雪路径最长,赚的钱最多)。我们可以将每条路的花费设置成负数,就可以了。有向边和无向边的区别我们可以建两个有向边。end
原创粉丝点击