bzoj1061 建图 + 最小费用流

https://www.lydsy.com/JudgeOnline/problem.php?id=106152

对于一个点对上多个点,不太容易建图的时候,考虑逆向思考

申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难
题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要
Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用
是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这
并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。
Input
  第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负
整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了
方便起见,我们可以认为每类志愿者的数量都是无限多的。
Output
  仅包含一个整数,表示你所设计的最优方案的总费用。

Sample Input
3 3
2 3 4
1 2 2
2 3 5
3 3 2
Sample Output
14
Hint
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。

题意

虽然我读完题知道这是一个费用流,但是始终想不到应该怎么建图,在我觉得这题不可能建图的时候看了一下题解。

才知道世界之大无奇不有。

原本正常的建图是以源点连到左边,志愿者连到他对应的天数,但是首先边会很多,并且费用也很难表示,建图的过程显得困难重重。

但是如果换一种方法。

我们将这个点需要多少个志愿者变成这个点还差多少个志愿者到达标准,标准我们设为一个大常数U。看起来好像没有区别,但是事实上我们从源点出U,经过每一天相当于经过了U - a[i]的限制,流量会减少,我们需要用志愿者来使她满流出去,所以对于一个L到R的志愿者,我们建立一条L 到 R + 1,费用为W的边即可,相当于这个志愿者填上了L 到 R的空缺。

真是神奇啊

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*10+c-‘0‘,c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 1e5 + 10;
const int maxm = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int U = 1e5 + 10;
const int mod = 1e9 + 7;
int N,M,K;
struct MCMF{
    struct Edge{
        int from,to,cap,flow,nxt;
        LL cost;
        Edge() {}
        Edge(int x,int y,int z,int u,LL v,int n){
            from = x; to = y; cap = z; flow = u; cost = v; nxt = n;
        }
    }edge[maxm];
    int E,n,head[maxn];
    int inq[maxn],d[maxn],p[maxn],a[maxn];
    inline void init(int _n){
        n = _n;E = 0;
        memset(head,-1,sizeof(head));
    }
    inline void addEdge(int f,int t,int c,LL w){
        edge[E] = Edge(f,t,c,0,w,head[f]);
        head[f] = E++;
        edge[E] = Edge(t,f,0,0,-w,head[t]);
        head[t] = E++;
    }
    bool spfa(int s,int t,int &flow,LL &cost){
        for(int i = 0 ; i <= n ; i ++) d[i] = INF;
        memset(inq,0,sizeof(inq));
        d[s] = 0;inq[s] = 1;p[s] = 0;a[s] = INF;
        queue<int>Q; Q.push(s);
        while(!Q.empty()){
            int u = Q.front(); Q.pop(); inq[u] = 0;
            for(int i = head[u]; ~i; i = edge[i].nxt){
                Edge &e = edge[i];
                if(e.cap <= e.flow || d[e.to] <= d[u] + e.cost) continue;
                d[e.to] = d[u] + e.cost;
                p[e.to] = i;
                a[e.to] = min(a[u],e.cap - e.flow);
                if(!inq[e.to]){
                    Q.push(e.to);
                    inq[e.to] = 1;
                }
            }
        }
        if(d[t] == INF) return false;
        flow += a[t];
        cost += (LL)d[t] * (LL)a[t];
        for(int u = t; u != s; u = edge[p[u]].from){
            edge[p[u]].flow += a[t];
            edge[p[u] ^ 1].flow -= a[t];
        }
        return true;
    }

    int mcmf(int s,int t,LL &cost){
        int flow = 0;
        cost = 0;
        while(spfa(s,t,flow,cost));
        return flow;
    }
}g;

int main()
{
    Sca2(N,M);
    int s = 0,t = N + 1;
    g.init(t + 1); g.addEdge(s,1,U,0);
    For(i,1,N){
        LL x; Scl(x);
        g.addEdge(i,i + 1,U - x,0);
    }
    while(M--){
        int l,r; LL c;
        Sca2(l,r); Scl(c);
        g.addEdge(l,r + 1,INF,c);
    }
    LL cost = 0; g.mcmf(s,t,cost);
    Prl(cost);
    #ifdef VSCode
    system("pause");
    #endif
    return 0;
}

原文地址:https://www.cnblogs.com/Hugh-Locke/p/9845762.html

时间: 2024-10-28 08:47:52

bzoj1061 建图 + 最小费用流的相关文章

POJ 2195 一人一房 最小费用流 建图 水题

Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 21010   Accepted: 10614 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 vertica

Random Maze (hdu 4067 最小费用流 好题 贪心思想建图)

Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1373    Accepted Submission(s): 514 Problem Description In the game "A Chinese Ghost Story", there are many random mazes which

River Problem (hdu 3947 流量等式建图 难题 最小费用最大流)

River Problem Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 515    Accepted Submission(s): 209 Problem Description The River of Bitland is now heavily polluted. To solve this problem, the Kin

UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的T-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据. 每组数据第一行是两个整数NN ,MM (N≤100N≤100 ,M≤10000M≤1000

poj1122 FDNY to the Rescue!(dij+反向建图+输出路径)

题目链接:poj1122 FDNY to the Rescue! 题意:给出矩阵,矩阵中每个元素tij表示从第i个交叉路口到第j个交叉路口所需时间,若tij为-1则表示两交叉路口之间没有直接路径,再给出火警位置所在的交叉路口 和 一个或多个消防站所处的交叉路口位置.输出要求按消防站到火警位置所需时间从小到大排列,输出信息包括消防站位置(初始位置),火警位置(目标位置),所需时间,最短路径上每个交叉路口. 题解:反向建图,从火警位置求一次最短路,求最短路时记录路径,按时间从小到大输出. 1 #in

HDU5772 String problem 最大权闭合图+巧妙建图

题意:自己看吧(不是很好说) 分析: 网络流:最大权闭合子图. 思路如下: 首先将点分为3类 第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分) 第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费) 第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x]) 那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点

4205: 卡牌配对 最大流+建图技巧

很明显该题应该是二分图最大匹配,但该题不可能N^2建图,那么我们要怎么办呢?而且有三个属性. 注意到 Ai <= 200 而且 200 以内的质数只有49个,那么我们就可以对着仅有的49个质数下毒手了.很明显如果 Ai 与 Aj 不互质的话, 两者应该有一个共同质因子. B和C同理. 那么我们可以在S集和T集中间建3层质因子的墙,分别为A和B, B和C, C和A. 只有当 Ai 被第 x 个质因子整除, Bi 被第 y 个质因子整除时, 我们从 i 往 P[0][x][y] 连边. 其他同理.

HDU5669 Road 分层最短路+线段树建图

分析:(官方题解) 首先考虑暴力,显然可以直接每次O(n^2) ?的连边,最后跑一次分层图最短路就行了. 然后我们考虑优化一下这个连边的过程 ,因为都是区间上的操作,所以能够很明显的想到利用线段树来维护整个图, 连边时候找到对应区间,把线段树的节点之间连边.这样可以大大缩减边的规模,然后再跑分层图最短路就可以了. 但是这样建图,每一次加边都要在O(logn)个线段树节点上加边,虽然跑的非常快,但是复杂度仍然是不科学的. 为了解决边的规模的问题,开两棵线段树,连边时候可以新建一个中间节点,在对应区

HDU3572Task Schedule(最大流 ISAP比较快)建图方法不错

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5007    Accepted Submission(s): 1636 Problem Description Our geometry princess XMM has stoped her study in computational geometry t