[NOI2008] 志愿者招募【最大流最小费用 经典问题】
2019-08-02 16:07
134 查看
洛谷连接
COGS题目连接
很好的一道题,我们要去处理区间问题,这里用到了一种很特殊,但是很好的算法。
因为天数是连续的,所以把第i天与第i+1天连接起来,费用为0、流量INF - a[i]。
然后再放一个第N+1天连接到T为INF的流,费用为0;
之后,我们要放对应的{ s[i], t[i], c[i] }是不是就可以往里面填充了,是不是可以直接s[i] -> t[i] + 1建立费用为c[i]的边即可。
[code]#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 #define INF 0x3f3f3f3f3f3f3f3f #define HalF (l + r)>>1 #define lsn rt<<1 #define rsn rt<<1|1 #define Lson lsn, l, mid #define Rson rsn, mid+1, r #define QL Lson, ql, qr #define QR Rson, ql, qr #define myself rt, l, r #define MP(x, y) make_pair(x, y) using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxN = 1e3 + 7, S = 0; int N, M, T; ll h[maxN], dist[maxN]; struct Eddge { int nex, u, v; ll flow, cost; Eddge(int a=-1, int b=0, int c=0, ll d=0, ll f=0):nex(a), u(b), v(c), flow(d), cost(f) {} }; vector<Eddge> G[maxN]; inline void _add(int u, int v, ll flow, ll cost) { G[u].push_back(Eddge((int)G[v].size(), u, v, flow, cost)); G[v].push_back(Eddge((int)G[u].size() - 1, v, u, 0, -cost)); } struct node { int id; ll val; node(int a=0, ll b=0):id(a), val(b) {} friend bool operator < (node e1, node e2) { return e1.val > e2.val; } }; priority_queue<node> Q; int preP[maxN], preE[maxN]; inline ll MaxFlow_MinCost(ll Flow) { ll ans = 0; for(int i=0; i<=T; i++) h[i] = 0; while(Flow) { for(int i=0; i<=T; i++) dist[i] = INF; dist[S] = 0; while(!Q.empty()) Q.pop(); Q.push(node(S, 0)); while(!Q.empty()) { node now = Q.top(); Q.pop(); int u = now.id; if(dist[u] < now.val) continue; int len = (int)G[u].size(); for(int i=0, v; i<len; i++) { v = G[u][i].v; ll f = G[u][i].flow, c = G[u][i].cost; if(f && dist[v] > dist[u] + c - h[v] + h[u]) { dist[v] = dist[u] + c - h[v] + h[u]; preP[v] = u; preE[v] = i; Q.push(node(v, dist[v])); } } } if(dist[T] == INF) break; for(int i=0; i<=T; i++) h[i] += dist[i]; ll Capa = Flow; for(int u=T; u != S; u = preP[u]) Capa = min(Capa, G[preP[u]][preE[u]].flow); Flow -= Capa; ans += Capa * h[T]; for(int u = T; u != S; u = preP[u]) { Eddge &E = G[preP[u]][preE[u]]; E.flow -= Capa; G[E.v][E.nex].flow += Capa; } } return ans; } inline void init() { T = N + 2; for(int i=0; i<=T; i++) G[i].clear(); } int main() { // freopen("employee.in", "r", stdin); // freopen("employee.out", "w", stdout); scanf("%d%d", &N, &M); init(); _add(S, 1, INF, 0); for(int i=1, val; i<=N; i++) { scanf("%d", &val); _add(i, i + 1, INF - val, 0); //免费部分 } for(int i=1, si, ti, ci; i<=M; i++) { scanf("%d%d%d", &si, &ti, &ci); _add(si, ti + 1, INF, ci); } _add(N + 1, T, INF, 0); printf("%lld\n", MaxFlow_MinCost(INF)); return 0; }
相关文章推荐
- P3980 [NOI2008](经典问题)志愿者招募 最小费用流
- [无源汇上下界最小费用可行流 差分费用流] BZOJ 1061 [Noi2008]志愿者招募
- BZOJ 1061 [Noi2008]志愿者招募(费用流)
- BZOJ.1061.[NOI2008]志愿者招募(线性规划 对偶原理 单纯形 / 费用流SPFA)
- bzoj1061 [Noi2008]志愿者招募(网络流解决线性规划问题)
- 动态规划经典问题03:数组中最大的数对差(或最小的数对差)
- 【费用流】NOI2008志愿者招募
- [BZOJ1061]-[Noi2008]志愿者招募-线性规划+费用流
- 【BZOJ1061】【NOI2008】志愿者招募 费用流神题、单纯形裸题(代码费用流)
- 【费用流】BZOJ1061[NOI2008]-志愿者招募
- 【网络流24题】分配问题 最小最大费用最大流
- bzoj1061-[Noi2008]志愿者招募-单纯形 & 费用流
- [BZOJ1061]NOI2008志愿者招募|费用流|线性规划
- [BZOJ 1061][Noi2008]志愿者招募:费用流|单纯型
- 【bzoj1061】[NOI2008]志愿者招募 线性规划与费用流
- 740. [网络流24题] 分配问题 费用流/求最大最小费用
- [NOI2008][bzoj1061] 志愿者招募 [费用流+巧妙的建图]
- 【费用流|单纯形】BZOJ1061 [Noi2008]志愿者招募
- 线性规划||网络流(费用流):COGS 288. [NOI2008] 志愿者招募
- bzoj1061 [Noi2008]志愿者招募(费用流)