网络流之最小费用最大流 P1251 餐巾计划问题
题目描述
一个餐厅在相继的 NN 天里,每天需用的餐巾数不尽相同。假设第 ii 天需要 r_iri块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 pp 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 nn 天(n>mn>m),其费用为 ss 分(s<fs<f)。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 NN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。
输入输出格式
输入格式:
由标准输入提供输入数据。文件第 1 行有 1 个正整数 NN,代表要安排餐巾使用计划的天数。
接下来的 NN 行是餐厅在相继的 NN 天里,每天需用的餐巾数。
最后一行包含5个正整数p,m,f,n,sp,m,f,n,s。pp 是每块新餐巾的费用; mm 是快洗部洗一块餐巾需用天数; ff 是快洗部洗一块餐巾需要的费用; nn 是慢洗部洗一块餐巾需用天数; ss 是慢洗部洗一块餐巾需要的费用。
输出格式:
将餐厅在相继的 N 天里使用餐巾的最小总花费输出
输入输出样例
说明
N<=2000
ri<=10000000
p,f,s<=10000
时限4s
const int INF = 0x3f3f3f3f;
const int maxn = + ;
struct edge
{
int u, v, c, f, cost;
edge(int u, int v, int c, int f, int cost):u(u), v(v), c(c), f(f), cost(cost){}
};
vector<edge>e;
vector<int>G[maxn];
int a[maxn];//找增广路每个点的水流量
int p[maxn];//每次找增广路反向记录路径
int d[maxn];//SPFA算法的最短路
int inq[maxn];//SPFA算法是否在队列中
int n, m;
void init(int n)
{
for(int i = ; i <= n; i++)G[i].clear();
e.clear();
}
void addedge(int u, int v, int c, int cost)
{
e.push_back(edge(u, v, c, , cost));
e.push_back(edge(v, u, , , -cost));
int m = e.size();
G[u].push_back(m - );
G[v].push_back(m - );
}
bool bellman(int s, int t, int& flow, long long & cost)
{
for(int i = ; i <= n + ; i++)d[i] = INF;//Bellman算法的初始化
memset(inq, , sizeof(inq));
d[s] = ;inq[s] = ;//源点s的距离设为0,标记入队
p[s] = ;a[s] = INF;//源点流量为INF(和之前的最大流算法是一样的) queue<int>q;//Bellman算法和增广路算法同步进行,沿着最短路拓展增广路,得出的解一定是最小费用最大流
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
inq[u] = ;//入队列标记删除
for(int i = ; i < G[u].size(); i++)
{
edge & now = e[G[u][i]];
int v = now.v;
if(now.c > now.f && d[v] > d[u] + now.cost)
//now.c > now.f表示这条路还未流满(和最大流一样)
//d[v] > d[u] + e.cost Bellman 算法中边的松弛
{
d[v] = d[u] + now.cost;//Bellman 算法边的松弛
p[v] = G[u][i];//反向记录边的编号
a[v] = min(a[u], now.c - now.f);//到达v点的水量取决于边剩余的容量和u点的水量
if(!inq[v]){q.push(v);inq[v] = ;}//Bellman 算法入队
}
}
}
if(d[t] == INF)return false;//找不到增广路
flow += a[t];//最大流的值,此函数引用flow这个值,最后可以直接求出flow
cost += (long long)d[t] * (long long)a[t];//距离乘上到达汇点的流量就是费用
for(int u = t; u != s; u = e[p[u]].u)//逆向存边
{
e[p[u]].f += a[t];//正向边加上流量
e[p[u] ^ ].f -= a[t];//反向边减去流量 (和增广路算法一样)
}
return true;
}
int MincostMaxflow(int s, int t, long long & cost)
{
cost = ;
int flow = ;
while(bellman(s, t, flow, cost));//由于Bellman函数用的是引用,所以只要一直调用就可以求出flow和cost
return flow;//返回最大流,cost引用可以直接返回最小费用
}
这个题目建图很难想,开始一点思路都没有,看了看题解。
建图:
这个是把每一天拆成了两个点,一个上午点和一个下午点。
下午点都和源点相连表示一天的结束,上午点和汇点相连,表示需要的餐巾数量。
与源点和汇点相连的点的cap都设置成这一天需要的餐巾数量,这个来限制送去快洗和慢洗的毛巾数。
然后再去处理3+1,3表示快洗,慢洗,新买,1表示不洗。因为之前以及被限制过了,
所以这里的不需要再去考虑有多少脏毛巾,这里的cap应该设置成inf,因为一次可以洗无数条毛巾。
这个不洗的要好好处理,这个不洗表示直接积累到下一天,那么就说明,这个的cost=0,
但是我们会疑惑,如果这样会不会影响到网络流? 其实这个不会,因为餐巾的积累会往下一天的晚上传递,意思
是说,这个餐巾不会算作这一天需要的餐巾数,但是那为什么还要连边呢?这个连边会让它往下一天传递,
那么餐巾积累,之后可以考虑一起洗掉。一起洗一堆和一次洗一条所用的时间是一样的,
所以如果我们之后再堆在一起洗也许会更优。
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 1e4;
struct node
{
int from, to, cap, flow, cost;
node(int from = , int to = , int cap = , int flow = , int cost = ) :from(from), to(to), cap(cap), flow(flow), cost(cost) {}
};
vector<node>e;
vector<int>G[maxn];
int s, t;
void add(int u, int v, int cap, int cost)
{
e.push_back(node(u, v, cap, , cost));
e.push_back(node(v, u, , , -cost));
int len = e.size();
G[u].push_back(len - );
G[v].push_back(len - );
}
int d[maxn], inq[maxn], a[maxn], p[maxn];
bool bellman(ll&cost)
{
for (int i = ; i <= t+; i++) d[i] = inf;
memset(inq, , sizeof(inq));
d[s] = , a[s] = inf;
inq[s] = ;
p[s] = ;
queue<int>que;
que.push(s);
while(!que.empty())
{
int u = que.front(); que.pop();
inq[u] = ;
for(int i=;i<G[u].size();i++)
{
node &now = e[G[u][i]];
if(now.cap>now.flow&&d[now.to]>d[u]+now.cost)
{
d[now.to] = d[u] + now.cost;
p[now.to] = G[u][i];
a[now.to] = min(a[u], now.cap - now.flow);
if(!inq[now.to])
{
que.push(now.to);
inq[now.to] = ;
}
}
}
}
if (d[t] == inf) return false;
cost += 1ll * d[t] * 1ll * a[t];
//printf("%lld\n", cost);
for(int i=t;i!=s;i=e[p[i]].from)
{
e[p[i]].flow += a[t];
e[p[i] ^ ].flow -= a[t];
}
return true;
} void Maxflow(ll &cost)
{
cost = ;
while (bellman(cost));
} int main()
{
int N;
cin >> N;
s = , t = * N + ;
for (int i = ; i <= N; i++)
{
int x;
cin >> x;
add(s, i, x, );
add(i + N, t, x, );
//printf("%d %d %d 0\n", s, i, x);
//printf("%d %d %d 0\n", i + N, t, x);
}
int q, m, f, n, g;
cin >> q >> m >> f >> n >> g;
for (int i = ; i <= N; i++)
{
if (i + <= N)
{
add(i, i + , inf, );
}
if (i + m <= N)
{
add(i, N + i + m, inf, f);
}
if (i + n <= N)
{
add(i, N + i + n, inf, g);
}
add(s, n + i, inf, q);
}
ll cost = ;
Maxflow(cost);
printf("%lld\n", cost);
return ;
}
网络流之最小费用最大流 P1251 餐巾计划问题的更多相关文章
- Libre 6008 「网络流 24 题」餐巾计划 (网络流,最小费用最大流)
Libre 6008 「网络流 24 题」餐巾计划 (网络流,最小费用最大流) Description 一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,-,N).餐厅可以从三种途径获得餐巾. ...
- Libre 6013 「网络流 24 题」负载平衡 (网络流,最小费用最大流)
Libre 6013 「网络流 24 题」负载平衡 (网络流,最小费用最大流) Description G 公司有n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使n ...
- Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流)
Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流) Description W 公司有m个仓库和n个零售商店.第i个仓库有\(a_i\)个单位的货物:第j个零售商店需要\( ...
- POJ 2135 Farm Tour (网络流,最小费用最大流)
POJ 2135 Farm Tour (网络流,最小费用最大流) Description When FJ's friends visit him on the farm, he likes to sh ...
- 网络流_spfa最小费用最大流
最大流: 不断搜索增广路,寻找最小的容量-流量,得到最大流量,但最大流量在有花费时不一定是最小花费. 最小费用最大流 算法思想: 采用贪心的思想,每次找到一条从源点到达汇点的花费最小的路径,增加流量, ...
- [cogs461] [网络流24题#10] 餐巾 [网络流,最小费用最大流]
建图:从源点向第一层连边,第一层表示当天用掉多少餐巾,第二层表示当天需要多少餐巾,所以注意购买餐巾的边容量为无穷大,要从源点开始连向第二层的点,每天可能有剩余,在第一层内表示为流入第二天的节点.具体见 ...
- LibreOJ #6008. 「网络流 24 题」餐巾计划 最小费用最大流 建图
#6008. 「网络流 24 题」餐巾计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- CGOS461 [网络流24题] 餐巾(最小费用最大流)
题目这么说的: 一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N).餐厅可以从三种途径获得餐巾. 购买新的餐巾,每块需p分: 把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f< ...
- 【COGS 461】[网络流24题] 餐巾 最小费用最大流
既然是最小费用最大流我们就用最大流来限制其一定能把每天跑满,那么把每个表示天的点向T连流量为其所需餐巾,费用为0的边,然后又与每天的餐巾对于买是无限制的因此从S向每个表示天的点连流量为INF,费用为一 ...
随机推荐
- LeetCode算法题-Jewels and Stones(Java实现)
这是悦乐书的第313次更新,第334篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第182题(顺位题号是771).字符串J代表珠宝,S代表你拥有的石头.S中的每个字符都是 ...
- 迷茫<第四篇:这两年>
时间匆匆而过,不知不觉已经是到北京的第二个年头,又到年末,2017年接近了尾声,提前预祝各位看官元旦节快乐! 今年3月份跳槽了一次,4月份以高级开发工程师职位进来现在的公司一直工作到现在,没有以前那么 ...
- Linux如何管理文档多租户
例题 同一群组microsoft下的两个账号justmine001和justmine002需要共同拥有目录/microsoft/eshop的开发权,以便进行协同工作,但是其他人不允许进入和查阅该目录. ...
- eShopOnWeb 知多少
1.引言 eShopOnWeb是基于ASP.NET Core构建,官方创建这样一个示例项目的目的,我想无非以下几点: 推广ASP.NET Core 指导利用ASP.NET Core如何进行架构设计 普 ...
- pycharm远程同步服务器代码,并设置权限
Pycharm开发工具链接至上面创建的虚拟环境链接 权限问题:此时上传还可能遇到权限问题,即使用的用户名没有权限在给定的目录下写入和修改文件. ubuntu权限管理:移动到指定目标上传文件夹的父文件夹 ...
- 解决 React-Native mac 运行报错 error Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65. To debug build logs further, consider building your app with Xcode.app, by ope
React-Native 开发的项目,Android 方面没有任何问题,IOS 就是无法跑起来,报错信息如下: mac 10.14.4 xcode 10.2.1 error Failed to bui ...
- java配置环境及安装
1.安装JDK开发环境 首先登陆https://www.oracle.com 第一步:Products ---- Java ---- Download java(JDK) for Developers ...
- ASP.NET Core Web API 集成测试中使用 Bearer Token
在 ASP.NET Core Web API 集成测试一文中, 我介绍了ASP.NET Core Web API的集成测试. 在那里我使用了测试专用的Startup类, 里面的配置和开发时有一些区别, ...
- 配置Nginx部署静态资源和自动跳转到https
一.首先在阿里云后台添加域名解析: 二.两个网站的静态资源在以下目录: /www/temp/blog/public 三.在服务器端配置nginx: cd /etc/nginx/conf.d 添加两个文 ...
- .Net—反射
在学习反射之前,先来理解以下几个概念. 1.什么是程序集? 程序集是.net中的概念. .Net中的dll文件与exe文件都是程序集.(exe与dll的区别?) exe文件是可执行文件,有执行入口.可 ...