码迷,mamicode.com
首页 > 其他好文 > 详细

费用流模板

时间:2018-08-11 10:50:19      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:距离   分享   false   amp   i++   反向   span   stream   建图   

 

技术分享图片

很好理解的,,按最大流思路理解就行  用优先队列优化复杂度低一点

//#include<iostream>
//#include<cstdio>
//#include<cstring>
//#include<cmath>
//#include<queue>
//#include<set>
//#include<algorithm>
//#include<map>
//#define maxn 200005
//typedef long long ll;
//#define inf 100000009
//using namespace std;
//struct edge{
//int to,cap,cost,rev;   //终点,容量,费用,反向边
//};
//int n,V;
//vector<edge>G[maxn];
//int dis[maxn];
//int prevv[maxn];  //最短路中的前驱结点
//int preve[maxn];  //最短路中对应的边
//
////向图中增加一条从from到头容量为cap费用为cost的边;
//void add_edge(int from,int to,int cap,int cost)
//{
//    G[from].push_back((edge){to,cap,cost,G[to].size()});
//    G[to].push_back((edge){from,0,-cost,G[from].size()-1});
//}
//
////求解从s到t流量为f的最小费用流
////如果不能再增广则返回-1
//int min_cost_flow(int V,int s,int t,int f)
//{
//    int res=0;
//    //cout<<V<<endl;
//    while(f>0)
//    {
//        fill(dis,dis+V,inf);
//        dis[s]=0;
//        bool vis=true;
//        while(vis)
//        {
//            //cout<<dis[3]<<endl;
//            // cout<<"a"<<endl;
//            vis=false;
//            //cout<<"a"<<endl;
//           // cout<<n<<endl;
//            for(int i=0;i<V;i++)
//            {
//                //cout<<dis[i]<<endl;
//                if(dis[i]==inf)continue;
//                for(int j=0;j<G[i].size();j++)
//                {
//                    edge &e=G[i][j];
//                    //cout<<e.cap<<endl;
//                    if(e.cap>0&&dis[e.to]>dis[i]+e.cost)
//                    {
//                        dis[e.to]=dis[i]+e.cost;
//                        prevv[e.to]=i;
//                        preve[e.to]=j;
//                        vis=true;
//                        //cout<<"vis"<<endl;
//                    }
//                }
//            }
//           // cout<<vis<<endl;
//        }
//        if(dis[t]==inf)return -1;  //表示不能增广
//        //沿s到t的最短路尽量增广
//         int d=f;
//         for(int i=t;i!=s;i=prevv[i])
//         {
//             d=min(d,G[prevv[i]][preve[i]].cap);
//         }
//         f-=d;
//         res+=d*dis[t];
//         for(int i=t;i!=s;i=prevv[i])
//         {
//             edge &e=G[prevv[i]][preve[i]];
//             e.cap-=d;
//             G[i][e.rev].cap+=d;
//         }
//    }
//    return res;
//}
//int main()
//{
//    int n,k;
//    cin>>n>>k;
//    int s1,t1,f1;
//    int x,y,z,l;
//    for(int i=0;i<k;i++)
//    {
//        cin>>x>>y>>z>>l;
//        add_edge(x,y,z,l);
//    }
//    cin>>s1>>t1>>f1;
//    cout<<min_cost_flow(n,s1,t1,f1)<<endl;
//    return 0;
//}




#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<algorithm>
#include<map>
#define maxn 20005
#define inf 1000000009
typedef long long ll;
using namespace std;
typedef pair<int,int>P;   //first保存最短距离   second保存顶点编号
struct edge{
int to,cap,cost,rev;
};
vector<edge>G[maxn];
int h[maxn];    //顶点的势
int dis[maxn];  //最短距离
int prevv[maxn]; //最短路中的前驱结点
int preve[maxn];   //最短路中的边
//建图
void add_edge(int from,int to,int cap,int cost)
{
    G[from].push_back((edge){to,cap,cost,G[to].size()});
    G[to].push_back((edge){from,0,-cost,G[from].size()-1});
}
//求解从s到t流量为f的最小费用流
//如果不能再增广则返回-1
int min_cost_flow(int V,int s,int t,int f)
{
    int res=0;
    fill(h,h+V,0);
    while(f>0)
    {
        priority_queue<P, vector<P>, greater<P> >que;
        fill(dis,dis+V,inf);
        dis[s]=0;
        que.push(P(0,s));
        while(!que.empty())
        {
            P p=que.top();
            que.pop();
            int v=p.second;
            if(dis[v]<p.first)continue;
            for(int i=0;i<G[v].size();i++)
            {
                edge &e=G[v][i];
                if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to])
                {
                    dis[e.to]=dis[v]+e.cost+h[v]-h[e.to];
                    prevv[e.to]=v;
                    preve[e.to]=i;
                    que.push(P(dis[e.to],e.to));
                }
            }
        }
        if(dis[t]==inf)return -1;
        for(int i=0;i<V;i++)
        {
            h[i]+=dis[i];
        }
        int d=f;
        for(int i=t;i!=s;i=prevv[i])
        {
            d=min(d,G[prevv[i]][preve[i]].cap);
        }
        f-=d;
        res+=d*h[t];
        for(int i=t;i!=s;i=prevv[i])
        {
            edge &e=G[prevv[i]][preve[i]];
            e.cap-=d;
            G[i][e.rev].cap+=d;
        }
    }
    return res;
}
int main()
{
    int n,k;
    cin>>n>>k;
    int s1,t1,f1;
    int x,y,z,l;
    for(int i=0;i<k;i++)
    {
        cin>>x>>y>>z>>l;
        add_edge(x,y,z,l);
    }
    cin>>s1>>t1>>f1;
    cout<<min_cost_flow(n,s1,t1,f1)<<endl;
    return 0;
}

 

费用流模板

标签:距离   分享   false   amp   i++   反向   span   stream   建图   

原文地址:https://www.cnblogs.com/huangzzz/p/9458709.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!