首页 > 代码库 > LibreOJ #102. 最小费用流

LibreOJ #102. 最小费用流

二次联通门 : LibreOJ #102. 最小费用流

 

 

 

 

/*
    LibreOJ #102. 最小费用流
    
    Spfa跑花费 
    记录路径
    倒推回去
     
*/
#include <cstring>
#include <cstdio>
#include <queue>

#define Max 10000

void read (int &now)
{
    now = 0;
    register char word = getchar ();
    while (word > 9 || word < 0)
        word = getchar ();
    while (word >= 0 && word <= 9)
    {
        now = now * 10 + word - 0;
        word = getchar ();
    }
}

inline int min (int a, int b)
{
    return a < b ? a : b;
}

class Cost_Flow_Type
{
    
    private :
        
        int __to[Max * 70];
        int __next[Max * 70];
        int __flow[Max * 70], __cost[Max * 70];
        
        int edge_list[Max];
        int Edge_Count;
        
        int dis[Max], can_flow[Max];
        bool visit[Max];
        int pre[Max];
        
    public :
        
        Cost_Flow_Type ()
        {
            Edge_Count = 1;
        }
        
        inline void Insert_edge (int from, int to, int flow, int cost)
        {
            Edge_Count ++;
            
            __to[Edge_Count] = to;
            __next[Edge_Count] = edge_list[from];
            edge_list[from] = Edge_Count;
            
            __flow[Edge_Count] = flow;
            __cost[Edge_Count] = cost;
            
            Edge_Count ++;
            
            __to[Edge_Count] = from;
            __next[Edge_Count] = edge_list[to];
            edge_list[to] = Edge_Count;
            
            __flow[Edge_Count] = 0;
            __cost[Edge_Count] = -cost;
        }
        
        bool Spfa (int Start, int End)
        {
            memset (dis, 0x3f, sizeof dis);
            memset (visit, false, sizeof visit);
            
            std :: queue <int> Queue;
            register int now;
            
            visit[Start] = true;
            can_flow[Start] = dis[0];
            pre[Start] = 0;
            
            for (Queue.push (Start), dis[Start] = 0; !Queue.empty (); Queue.pop ())
            {
                now = Queue.front ();
                
                visit[now] = false;
                
                for (int i = edge_list[now]; i; i = __next[i])
                    if (__flow[i] && dis[__to[i]] > dis[now] + __cost[i])
                    {
                        dis[__to[i]] = dis[now] + __cost[i];
                        pre[__to[i]] = i;
                        
                        can_flow[__to[i]] = min (can_flow[now], __flow[i]);
                        
                        if (!visit[__to[i]])
                        {
                            Queue.push (__to[i]);
                            visit[__to[i]] = true; 
                        }
                    }
            }
            
            return dis[End] < dis[0];
        }
        
        void Get_Cost_Flow (int Start, int End)
        {
            int res = 0;
            int Cost_ = 0;
            for (int x; Spfa (Start, End); )
            {
                x = can_flow[End];
                for (int i = End; i != Start; i = __to[pre[i] ^ 1])
                {
                    __flow[pre[i]] -= x;
                    __flow[pre[i] ^ 1] += x;
                }
                res += x;
                Cost_ += dis[End] * x;
            }
            
            printf ("%d %d", res, Cost_);
        }
};

int N, M;

Cost_Flow_Type Make;

int main (int argc, char *argv[])
{
    int x, y, z, Flandre;
    
    for (read (N), read (M); M --; )
    {
        read (x);
        read (y);
        read (z);
        read (Flandre);
        
        Make.Insert_edge (x, y, z, Flandre); 
    }
    
    Make.Get_Cost_Flow (1, N);
    
    return 0;
}

 

LibreOJ #102. 最小费用流