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;
}
时间: 2024-10-12 09:01:03

LibreOJ #102. 最小费用流的相关文章

loj 102 最小费用流

补一发费用流的代码 %%%棒神 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #define l

FZU2143Board Game(最小费用流)

题目大意是说有一个B矩阵,现在A是一个空矩阵(每个元素都为0),每次操作可以将A矩阵相邻的两个元素同时+1,但是有个要求就是A矩阵的每个元素都不可以超过K,求 这个的最小值 解题思路是这样的,新建起点与奇点(i != j)连K条边,第i条边的权值为(i - B)^2 - (i - 1 - B)^2 = 2 * i - 1 - 2 * B(这样可以保证如果此边的流量为a, 花费始终是(a-b)^2);另外新建终点与偶点相连,代价与上诉一致: 然后跑一遍最小费用流,知道cost>=0时为止.祥见代码

UVa 1658 (拆点法 最小费用流) Admiral

题意: 给出一个有向带权图,求从起点到终点的两条不相交路径使得权值和最小. 分析: 第一次听到“拆点法”这个名词. 把除起点和终点以外的点拆成两个点i和i',然后在这两点之间连一条容量为1,费用为0的边.这样就保证了每个点最多经过一次. 其他有向边的容量也是1 然后求从起点到终点的流量为2(这样就保证了是两条路径)的最小费用流. 本来要在加一个源点和汇点来限制流量的,但是这样弧就多了很多.lrj代码中用了很巧妙的方法,避免了这个问题. 1 #include <bits/stdc++.h> 2

POJ 2516:Minimum Cost(最小费用流)

https://vjudge.net/problem/11079/origin 题意:有N个商店和M个供应商和K种物品,每个商店每种物品有一个需求数,每个供应商每种物品有一个供应量,供应商到商店之间的运输需要花费,如果供不应求输出-1,否则输出最小花费. 思路:比较明显的最小费用流.想法大概都是源点和供应商连一条容量为供应量,花费为0的边,商店和汇点之间连一条容量为需求量,花费为0的边,供应商和商店之间连一条容量为INF,花费为题意给出的花费的边.建图的话一开始是直接对于每一个商店每一种物品和每

(最小费用流)hdu 6118(2017百度之星初赛B 1005) 度度熊的交易计划

度度熊的交易计划 Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 260    Accepted Submission(s): 83 Problem Description 度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题: 喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区. 由于生产能力的区别,第i个片

POJ 2195 Going Home 最小费用流 裸题

给出一个n*m的图,其中m是人,H是房子,.是空地,满足人的个数等于房子数. 现在让每个人都选择一个房子住,每个人只能住一间,每一间只能住一个人. 每个人可以向4个方向移动,每移动一步需要1$,问所有人移动到房子里的最少花费. 其中,n,m<=100,最多有100个人. 最小给用流裸题. 建立一个超级源点,跟每一个房子连一条边,容量为1,花费为0 每一个人与超级汇点连一条边,容量为1,花费为0 一个房子与每一个人建一条边,房子指向人,容量为1,花费用2者的距离(不是直线距离) 然后跑最小费用流算

【HDOJ6118】度度熊的交易计划(最小费用流)

题意: 度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题: 喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区. 由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但是最多生产b[i]个. 同样的,由于每个片区的购买能力的区别,第i个片区也能够以c[i]的价格出售最多d[i]个物品. 由于这些因素,度度熊觉得只有合理的调动物品,才能获得最大的利益. 据测算,每一个商品运输1公里,将会花费1元. 那么喵哈哈村最多能够实现多少盈利呢? 1<=n<=500,

最小费用流 poj2195

Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17955   Accepted: 9145 Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertical

UVA 1659 Help Little Laura (最小费用流,最小循环流)

(同时也是HDU 2982,UVA的数据多) 题意:平面上有m条有向线段连接了n个点.你从某个点出发顺着有向线段行走,给走过的每条线段涂一种不同的颜色,最后回到起点.你可以多次行走,给多个回路涂色(要么不涂色,要么就至少给一个回路上的边全部涂色).可以重复经过一个点,但不能重复经过一条有向线段.如下图所示的是一种涂色方法(虚线表示未涂色,即每次都可以从任意点出发染色).每涂一个单位长度将得到X分,但每使用一种颜色将扣掉Y分.假设你拥有无限多种的颜色,问如何涂色才能使得分最大?输入保证若存在有向线