1. 程式人生 > >bzoj1221軟體開發 費用流

bzoj1221軟體開發 費用流

題目傳送門

思路:

  網路流拆點有的是“過程拆點”,有的是“狀態拆點”,這道題應該就屬於狀態拆點。

  每個點分需要用的,用完的。

  對於需要用的,這些毛巾來自新買的和用過的毛巾進行消毒的,流向終點。

  對於用完的,來自源點,可以用於消毒,連向需要用的點,還有一些毛巾留到明天消毒(其實意思是,消完毒,延後使用,但是這樣建邊麻煩)。

  挺不錯的題目吧。

  一個非常坑的地方就是,a和b可能大於1000,所以拆點的點的編號要很小心,要判斷一下是否越界。

  推薦一個部落格。大佬的部落格

#include<bits/stdc++.h>
#define
CLR(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int MAXN = 10010; const int MAXM = 100010; const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow, cost; } edge[MAXM]; struct pp { int u,v,c,w; } in[MAXN]; int head[MAXN], tol; int pre[MAXN], dis[MAXN]; int n,a,b,f,fa,fb;
int aa[2010]; bool vis[MAXN]; int N=MAXN-2; void init() { tol = 0; memset(head, -1, sizeof(head)); } void addv(int u, int v, int cap, int cost) { // printf("u:%d v:%d cap:%d cost:%d\n",u,v,cap,cost); edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow
= 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s, int t) { queue<int>q; CLR(dis,INF); CLR(vis,0),CLR(pre,-1); dis[s] = 0; vis[s] = true; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = true; q.push(v); } } } } if (pre[t] == -1)return false; else return true; } //返回的是最大流,cost 存的是最小費用 int minCostMaxflow(int s, int t, int &cost) { int flow = 0; cost = 0; while (spfa(s, t)) { int Min = INF; for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) { if (Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; //printf("debug\n"); } for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) { edge[i].flow += Min; edge[i ^ 1].flow -= Min; cost += edge[i].cost * Min; } flow += Min; } return flow; } int main() { cin>>n>>a>>b>>f>>fa>>fb; init(); for(int i=1;i<=n;i++) { scanf("%d",&aa[i]); } int s=0,p=1000,t=3010; for(int i=1;i<=n;i++) { addv(s,i,aa[i],0); addv(i+p,t,aa[i],0); addv(s,i+p,INF,f); if(i+a<=n) addv(i,i+a+p+1,INF,fa); if(i+b<=n) addv(i,i+b+p+1,INF,fb); if(i+1<=n) addv(i,i+1,INF,0); } int cost; minCostMaxflow(s,t,cost); printf("%d\n",cost); }
View Code

1221: [HNOI2001] 軟體開發

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2103  Solved: 1217
[Submit][Status][Discuss]

Description

某軟體公司正在規劃一項n天的軟體開發計劃,根據開發計劃第i天需要ni個軟體開發人員,為了提高軟體開發人員的效率,公司給軟體人員提供了很多的服務,其中一項服務就是要為每個開發人員每天提供一塊消毒毛巾,這種消毒毛巾使用一天後必須再做消毒處理後才能使用。消毒方式有兩種,A種方式的消毒需要a天時間,B種方式的消毒需要b天(b>a),A種消毒方式的費用為每塊毛巾fA, B種消毒方式的費用為每塊毛巾fB,而買一塊新毛巾的費用為f(新毛巾是已消毒的,當天可以使用);而且f>fA>fB。公司經理正在規劃在這n天中,每天買多少塊新毛巾、每天送多少塊毛巾進行A種消毒和每天送多少塊毛巾進行B種消毒。當然,公司經理希望費用最低。你的任務就是:為該軟體公司計劃每天買多少塊毛巾、每天多少塊毛巾進行A種消毒和多少毛巾進行B種消毒,使公司在這項n天的軟體開發中,提供毛巾服務的總費用最低。

Input

第1行為n,a,b,f,fA,fB. 第2行為n1,n2,……,nn. (注:1≤f,fA,fB≤60,1≤n≤1000)

Output

最少費用

Sample Input

4 1 2 3 2 1
8 2 1 6

Sample Output

38