[BZOJ1061][Noi2008]志愿者招募
[BZOJ1061][Noi2008]志愿者招募
试题描述
申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难
输入
第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负
输出
仅包含一个整数,表示你所设计的最优方案的总费用。
输入示例
输出示例
数据规模及约定
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。
题解
NOI的题目就是好。。。既能学新姿势还能轻松A掉。。。
这是一道费用流的题目,但是它的解题思路是基于流量平衡的。这类题可以搜集题目中的限制条件列出等式,转化成 A - B = 0 的形式,那么将该等式作为一个节点,A 就是流入的流量,B 即为流出的流量。
详细题解:https://www.byvoid.com/blog/noi-2008-employee/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
if(Head == tail) {
int l = fread(buffer, 1, BufferSize, stdin);
tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 1010
#define maxm 24012
#define oo 2147483647
#define ool 1ll << 60
#define LL long long
struct Edge { int from, to, flow, cost; } ;
struct ZKW {
int n, m, s, t, head[maxn], next[maxm];
Edge es[maxm];
LL d[maxn];
bool vis[maxn];
LL ans, cost;
void init(int nn) {
n = nn; m = 0;
memset(head, -1, sizeof(head));
return ;
}
void AddEdge(int a, int b, int c, int d) {
es[m] = (Edge){ a, b, c, d }; next[m] = head[a]; head[a] = m++;
es[m] = (Edge){ b, a, 0, -d }; next[m] = head[b]; head[b] = m++;
return ;
}
bool BFS() {
for(int i = 1; i <= n; i++) d[i] = ool;
d[t] = 0;
deque <int> Q; Q.push_front(t);
while(!Q.empty()) {
int u = Q.front(); Q.pop_front();
for(int i = head[u]; i != -1; i = next[i]) {
Edge& e = es[i^1];
if(e.flow && d[e.from] > d[u] + e.cost) {
d[e.from] = d[u] + e.cost;
if(Q.empty() || d[e.from] <= d[Q.front()]) Q.push_front(e.from);
else Q.push_back(e.from);
}
}
}
if(d[s] == ool) return 0;
for(int i = 0; i < m; i++) es[i].cost += d[es[i].to] - d[es[i].from];
cost += d[s];
return 1;
}
int DFS(int u, int a) {
if(u == t || !a){ ans += cost * a; return a; }
int flow = 0, f;
vis[u] = 1;
for(int i = head[u]; i != -1; i = next[i]) {
Edge& e = es[i];
if(!vis[e.to] && !e.cost && (f = DFS(e.to, min(a, e.flow)))) {
flow += f; a -= f;
e.flow -= f; es[i^1].flow += f;
if(!a) return flow;
}
}
return flow;
}
int MaxFlow(int ss, int tt) {
s = ss; t = tt;
int flow = 0, f;
while(BFS())
do {
memset(vis, 0, sizeof(vis));
f = DFS(s, oo);
flow += f;
} while(f);
return flow;
}
} sol; int main() {
int n = read(), m = read();
sol.init(n + 3); int s = n + 2, t = n + 3;
int lastA = 0, A;
for(int i = 1; i <= n; i++) {
A = read();
if(A - lastA > 0) sol.AddEdge(s, i, A - lastA, 0);
else sol.AddEdge(i, t, lastA - A, 0);
sol.AddEdge(i + 1, i, oo, 0);
lastA = A;
}
sol.AddEdge(n + 1, t, A, 0);
for(int i = 1; i <= m; i++) {
int x = read(), y = read(), c = read();
sol.AddEdge(x, y + 1, oo, c);
} sol.MaxFlow(s, t);
printf("%lld\n", sol.ans); return 0;
}
/*
3 3
2 3 4
1 2 2
2 3 5
3 3 2
*/
这个题还有一个不用线性规划的做法:我们跑可行流。
对于每一天,流量下界为每天需要的志愿者人数,然后对于一个从第 s 天到第 t 天的志愿者,从这个志愿者向第 s 天连边(容量无穷费用为该志愿者的费用),然后从第 t 天向该志愿者连边(容量无穷费用为 0)。
我的代码搞了一个小优化,每天没有拆点,而是把一条边看成一天,所以加边成环时会有一些小边界问题要考虑。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--) int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 11111
#define maxm 46010
#define oo 2147483647
#define ool (1ll << 60)
#define LL long long struct Edge {
int from, to, flow, cost;
Edge() {}
Edge(int _1, int _2, int _3, int _4): from(_1), to(_2), flow(_3), cost(_4) {}
};
struct ZKW {
int n, m, s, t, head[maxn], nxt[maxm];
LL cost, ans;
Edge es[maxm];
LL d[maxn];
int Q[maxn*10], hd, tl;
bool inq[maxn];
bool vis[maxn]; void init() {
m = 0; memset(head, -1, sizeof(head));
return ;
}
void setn(int _) {
n = _;
return ;
} void AddEdge(int a, int b, int c, int d) {
es[m] = Edge(a, b, c, d); nxt[m] = head[a]; head[a] = m++;
es[m] = Edge(b, a, 0, -d); nxt[m] = head[b]; head[b] = m++;
return ;
} bool BFS() {
rep(i, 1, n) d[i] = ool;
d[t] = 0;
hd = tl = 0; Q[++tl] = t; inq[t] = 1;
while(hd < tl) {
int u = Q[++hd]; inq[u] = 0;
for(int i = head[u]; i != -1; i = nxt[i]) {
Edge& e = es[i^1];
if(d[e.from] > d[u] + e.cost && e.flow) {
d[e.from] = d[u] + e.cost;
if(!inq[e.from]) {
inq[e.from] = 1;
Q[++tl] = e.from;
}
}
}
}
if(d[s] == ool) return 0;
cost = d[s];
return 1;
} int DFS(int u, int a) {
if(u == t || !a) return ans += cost * a, a;
if(vis[u]) return 0;
vis[u] = 1;
int flow = 0, f;
for(int i = head[u]; i != -1; i = nxt[i]) {
Edge& e = es[i];
if(d[e.to] == d[u] - e.cost && (f = DFS(e.to, min(a, e.flow)))) {
flow += f; a -= f;
e.flow -= f; es[i^1].flow += f;
if(!a) return flow;
}
}
return flow;
} int MaxFlow(int _s, int _t) {
s = _s; t = _t;
int flow = 0, f;
while(BFS())
do {
memset(vis, 0, sizeof(vis));
f = DFS(s, oo);
flow += f;
} while(f);
return flow;
}
} sol; #define maxdays 1010
#define maxvol 10010 int CntP;
struct Point {
int id;
Point(): id(0) {}
int p() { return id ? id : id = ++CntP; }
} Days[maxdays], Vol[maxvol], S, T; int main() {
int days = read(), vol = read();
sol.init();
rep(i, 1, days) {
int lim = read();
sol.AddEdge(S.p(), Days[i+1].p(), lim, 0);
sol.AddEdge(Days[i].p(), T.p(), lim, 0);
sol.AddEdge(Days[i].p(), Days[i+1].p(), oo - lim, 0);
}
rep(i, 1, vol) {
int s = read(), t = read(), c = read();
sol.AddEdge(Vol[i].p(), Days[s].p(), oo, c);
sol.AddEdge(Days[t+1].p(), Vol[i].p(), oo, 0);
}
sol.setn(CntP); sol.MaxFlow(S.p(), T.p());
printf("%lld\n", sol.ans); return 0;
}
[BZOJ1061][Noi2008]志愿者招募的更多相关文章
- 网络流解线性规划问题 BZOJ1061: [Noi2008]志愿者招募
线性规划定义: 在给定有限的资源和竞争约束情况下,很多问题都可以表述为最大化或最小化某个目标.如果可以把目标指定为某些变量的线性函数,而且如果可以将资源约束指定为这些变量的等式或不等式,则得到了一个线 ...
- 【费用流】BZOJ1061: [Noi2008]志愿者招募(这题超好)
1061: [Noi2008]志愿者招募 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 5291 Solved: 3173[Submit][Stat ...
- [BZOJ1061] [Noi2008] 志愿者招募 (费用流)
Description 申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难 题:为即将启动的奥运新项目招募一批短期志愿者.经过估算,这个项目需要N 天才能 ...
- BZOJ1061 [Noi2008]志愿者招募 【单纯形】
题目链接 BZOJ1061 题解 今天终于用正宗的线性规划\(A\)了这道题 题目可以看做有\(N\)个限制和\(M\)个变量 变量\(x_i\)表示第\(i\)种志愿者的人数,对于第\(i\)种志愿 ...
- 【费用流】BZOJ1061[NOI2008]-志愿者招募
[题目大意] 一个项目需要n天完成,其中第i天至少需要Ai个人.共有m类人可以招募,其中第i类可以从第Si天做到第Ti天,每人的招募费用为Ci元.求最小招募费用. [思路] byvoid神犇的建图详解 ...
- BZOJ1061: [Noi2008]志愿者招募(线性规划)
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 5725 Solved: 3437[Submit][Status][Discuss] Descript ...
- BZOJ1061 NOI2008 志愿者招募 线性规划、费用流
传送门 一道思路很妙的线性规划网络流 设\(X_i\)表示第\(i\)天需要的人数,\(P_i\)表示第\(i\)种人雇佣的个数 那么我们可以列出一系列式子 比如说样例就可以列出三个式子: \(P_1 ...
- 线性规划费用流解法(Bzoj1061: [Noi2008]志愿者招募)
题面 传送门 Sol 线性规划费用流解法用与求解未知数为非负数的问题 这道题可以列出一堆形如 \(x[i]+x[j]+x[k]+...>=a[p]\) 的不等式 我们强行给每个式子减去一个东西, ...
- [BZOJ1061][Noi2008]志愿者招募 线性规划+费用流
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1061 根据题意列方程,然后用网络流解线性规划. 题解直接贴ByVoid的吧,太神了:htt ...
随机推荐
- [BZOJ 3143][HNOI2013]游走(数学期望)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3143 分析: 易得如果知道了每条边经过的数学期望,那就可以贪心着按每条边的期望的大小赋 ...
- DOM系列---进阶篇
内容提纲: 1.DOM类型 2.DOM扩展 3.DOM操作内容 一.DOM类型 DOM基础篇中,我们了解了DOM的节点并且了解怎样查询和操作节点,而本身这些不同的节点,又有着不同的类型. DOM类 ...
- 通过smtp协议简单实现邮件发送
使用到的类: ①SmtpClient--发送邮件的类(using System.Net.Mail;) ②MailMessage--初始化邮件的类 ③ NetworkCredential--身份验证的类 ...
- MVC升级以后出现"当前上下文中不存在ViewBag"的问题解决
把自己的项目从MVC4升级到了MVC5,结果问题一大堆,View的设计环境出现了"当前上下文中不存在ViewBag"的问题: 虽然不影响编译,但是看了总是不爽,而且语法提示也没有了 ...
- Java.util.ArrayList详解
java.util.ArrayList就是传说中的动态数组. 继承了关系,有此可看出ArrayList与list的collection的关系 public class ArrayList<E&g ...
- Rdesktop
linux远程windows rdesktop是一个开放源码的Window NT中断服务器的客户端,它实现了远程桌面协议(RDP) rdesktop-1.7.0.tar 下载地址:http://d ...
- bzoj 2815 灾难
首先假设我们定义x灭绝后y会灭绝,那么离y最近的x就为y的父亲节点,那么如果我们可以求出每个节点的父亲节点,我们就得到了一棵树,然后每个节点的灾难值就是子树的大小-1. 我们将出度数为0的节点的父亲节 ...
- h5页面,改变数字默认颜色
最近遇到一个非常变态的bug,有一串数字,我设置color为白色,在pc端浏览器,无变化,但是到了手机端,会由白色跳成黑色,我无解啊... 刚刚找到方法,如下: <meta name=" ...
- Treap实现山寨set
treap插入.删除.查询时间复杂度均为O(logn) treap树中每个节点有两种权值:键值和该节点优先值 如果只看优先值,这棵树又是一个堆 treap有两种平衡方法:左旋&右旋 inser ...
- schemaLocation value = 'xxxxxxxxxxxx' must have even number of URI's
这是因为没有加上Spring的版本号,加上就行了,如: http://www.springframework.org/schema/beans/spring-beans.xsd -3.2.2 http ...