餐巾计划问题 费用流
题目描述
一个餐厅在相继的 NNN 天里,每天需用的餐巾数不尽相同。假设第 iii 天需要 rir_iri块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 ppp 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 nnn 天(n>mn>mn>m),其费用为 sss 分(s<fs<fs<f)。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 NNN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。
输入输出格式
输入格式:由标准输入提供输入数据。文件第 1 行有 1 个正整数 NNN,代表要安排餐巾使用计划的天数。
接下来的 NNN 行是餐厅在相继的 NNN 天里,每天需用的餐巾数。
最后一行包含5个正整数p,m,f,n,sp,m,f,n,sp,m,f,n,s。ppp 是每块新餐巾的费用; mmm 是快洗部洗一块餐巾需用天数; fff 是快洗部洗一块餐巾需要的费用; nnn 是慢洗部洗一块餐巾需用天数; sss 是慢洗部洗一块餐巾需要的费用。
输出格式:将餐厅在相继的 N 天里使用餐巾的最小总花费输出
输入输出样例
说明
N<=2000
ri<=10000000
p,f,s<=10000
时限4s
重要是建图;
将每一天分为早上和晚上;
s向每一天晚上连容量为ri,费用为0的边,每一天早上向t连容量为ri,费用为0的边;
第 i 天晚上可以向第 i+1 天晚上连边,对于清洗来说,第 i 天晚上可以向 第 i+T1/T2 天早上连边;
最后每一天早上都可以花费 p 来购买毛巾;
#include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<vector> #include<queue> #include<bitset> #include<ctime> #include<deque> #include<stack> #include<functional> #include<sstream> //#include<cctype> //#pragma GCC optimize(2) using namespace std; #define maxn 200005 #define inf 0x7fffffff //#define INF 1e18 #define rdint(x) scanf("%d",&x) #define rdllt(x) scanf("%lld",&x) #define rdult(x) scanf("%lu",&x) #define rdlf(x) scanf("%lf",&x) #define rdstr(x) scanf("%s",x) typedef long long ll; typedef unsigned long long ull; typedef unsigned int U; #define ms(x) memset((x),0,sizeof(x)) const long long int mod = 1e9; #define Mod 1000000000 #define sq(x) (x)*(x) #define eps 1e-5 typedef pair<int, int> pii; #define pi acos(-1.0) //const int N = 1005; #define REP(i,n) for(int i=0;i<(n);i++) typedef pair<int, int> pii; inline int rd() { int x = 0; char c = getchar(); bool f = false; while (!isdigit(c)) { if (c == '-') f = true; c = getchar(); } while (isdigit(c)) { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return f ? -x : x; } ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a%b); } int sqr(int x) { return x * x; } /*ll ans; ll exgcd(ll a, ll b, ll &x, ll &y) { if (!b) { x = 1; y = 0; return a; } ans = exgcd(b, a%b, x, y); ll t = x; x = y; y = t - a / b * y; return ans; } */ bool vis[maxn]; int n, m, s, t; int x, y, f, z; ll dis[maxn], pre[maxn], last[maxn], flow[maxn]; ll maxflow, mincost; struct node { ll to, nxt, flow, dis; }edge[maxn << 2]; int head[maxn], cnt; queue<int>q; void addedge(int from, int to, int flow, int dis) { edge[++cnt].to = to; edge[cnt].flow = flow; edge[cnt].dis = dis; edge[cnt].nxt = head[from]; head[from] = cnt; } bool spfa(int s, int t) { memset(dis, 0x7f, sizeof(dis)); memset(flow, 0x7f, sizeof(flow)); ms(vis); q.push(s); vis[s] = 1; dis[s] = 0; pre[t] = -1; while (!q.empty()) { int now = q.front(); q.pop(); vis[now] = 0; for (int i = head[now]; i != -1; i = edge[i].nxt) { if (edge[i].flow > 0 && dis[edge[i].to] > dis[now] + edge[i].dis) { dis[edge[i].to] = edge[i].dis + dis[now]; pre[edge[i].to] = now; last[edge[i].to] = i; flow[edge[i].to] = min(flow[now], edge[i].flow); if (!vis[edge[i].to]) { vis[edge[i].to] = 1; q.push(edge[i].to); } } } } return pre[t] != -1; } void mincost_maxflow() { while (spfa(s, t)) { int now = t; maxflow += flow[t]; mincost += flow[t] * dis[t]; while (now != s) { edge[last[now]].flow -= flow[t]; edge[last[now] ^ 1].flow += flow[t]; now = pre[now]; } } } int main() { //ios::sync_with_stdio(0); memset(head, -1, sizeof(head)); cnt = 1; n = rd(); s = 0; t = 2 * n + 2; for (int i = 1; i <= n; i++) { int x; x = rd(); addedge(s, i, x, 0); addedge(i, s, 0, 0); addedge(i + n, t, x, 0); addedge(t, i + n, 0, 0); } int p; int m1, t1, m2, t2; p = rd(); t1 = rd();m1 = rd(); t2 = rd(); m2 = rd(); for (int i = 1; i <= n; i++) { if (i + 1 <= n)addedge(i, i + 1, inf, 0), addedge(i + 1, i, 0, 0); if (i + t1 <= n)addedge(i, i + t1 + n, inf, m1), addedge(i + t1 + n, i, 0, -m1); if (i + t2 <= n)addedge(i, i + t2 + n, inf, m2), addedge(i + t2 + n, i, 0, -m2); addedge(s, i + n, inf, p), addedge(i + n, s, 0, -p); } mincost_maxflow(); printf("%lld\n", 1ll * mincost); return 0; }
EPFL - Fighting