bzoj 1221: [HNOI2001] 软件开发
思路:把每天拆乘两个点Xi, Yi 两堆点
建边过程:
1、从S向每个Xi连一条容量为a[ i ],费用为0的有向边。
2、从每个Yi向T连一条容量为a[ i ],费用为0的有向边。
3、从S向每个Yi连一条容量为inf,费用为c1的有向边。
4、从每个Xi向Xi + 1(i+1<=N)连一条容量为inf,费用为0的有向边。
5、从每个Xi向Yi + p + 1(i + p + 1 <= N)连一条容量为inf,费用为f的有向边。
6、从每个Xi向Yi + q + 1(i + q + 1<=N)连一条容量为inf,费用为s的有向边。
注意:能少建边就少见边,我刚开始因为建了接近n^2的边就T啦。。
费用流拉的别人的板子, 有空自己手敲一个。。。
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define fi first 4 #define se second 5 #define mk make_pair 6 #define pii pair<int,int> 7 #define piii pair<int,pair<int,int>> 8 9 using namespace std; 10 11 const int N = 2000 + 7; 12 const int M = 5e5 + 7; 13 const int inf = 0x3f3f3f3f; 14 const LL INF = 0x3f3f3f3f3f3f3f3f; 15 const int mod = 1e9 + 7; 16 17 int n, p, q, c1, c2, c3, a[N]; 18 19 struct Edge 20 { 21 int from, to, cap, flow, cost, next; 22 }; 23 Edge edge[M]; 24 int head[N], edgenum; 25 int pre[N]; 26 int dist[N]; 27 bool vis[N]; 28 int source, sink; 29 void init() 30 { 31 edgenum = 0; 32 memset(head, -1, sizeof(head)); 33 } 34 void addEdge(int u, int v, int w, int c) 35 { 36 Edge E1 = {u, v, w, 0, c, head[u]}; 37 edge[edgenum] = E1; 38 head[u] = edgenum++; 39 Edge E2 = {v, u, 0, 0, -c, head[v]}; 40 edge[edgenum] = E2; 41 head[v] = edgenum++; 42 } 43 bool SPFA(int s, int t) 44 { 45 queue<int> Q; 46 memset(dist, INF, sizeof(dist)); 47 memset(vis, false, sizeof(vis)); 48 memset(pre, -1, sizeof(pre)); 49 dist[s] = 0; 50 vis[s] = true; 51 Q.push(s); 52 while(!Q.empty()) 53 { 54 int u = Q.front(); 55 Q.pop(); 56 vis[u] = false; 57 for(int i = head[u]; i != -1; i = edge[i].next) 58 { 59 Edge E = edge[i]; 60 if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow) 61 { 62 dist[E.to] = dist[u] + E.cost; 63 pre[E.to] = i; 64 if(!vis[E.to]) 65 { 66 vis[E.to] = true; 67 Q.push(E.to); 68 } 69 } 70 } 71 } 72 return pre[t] != -1; 73 } 74 void MCMF(int s, int t, LL &cost, int &flow) 75 { 76 flow = 0; 77 cost = 0; 78 while(SPFA(s, t)) 79 { 80 int Min = INF; 81 for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 82 { 83 Edge E = edge[i]; 84 Min = min(Min, E.cap - E.flow); 85 } 86 //增广 87 for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 88 { 89 edge[i].flow += Min; 90 edge[i^1].flow -= Min; 91 cost += edge[i].cost * Min; 92 } 93 flow += Min; 94 } 95 } 96 int main() { 97 init(); 98 scanf("%d%d%d%d%d%d", &n, &p, &q, &c1, &c2, &c3); 99 source = 0, sink = 2 * n + 1; 100 for(int i = 1; i <= n; i++) { 101 scanf("%d", &a[i]); 102 addEdge(source, i + n, a[i], c1); 103 addEdge(i + n, sink, a[i], 0); 104 addEdge(source, i, a[i], 0); 105 } 106 107 for(int i = 1; i <= n; i++) { 108 for(int j = i + p + 1; j < i + q + 1 && j <= n; j++) 109 addEdge(i, j + n, a[i], c2); 110 for(int j = i + q + 1; j <= n; j++) 111 addEdge(i, j + n, a[i], c3); 112 } 113 114 LL cost; 115 int flow; 116 MCMF(source, sink, cost, flow); 117 printf("%lld\n", cost); 118 return 0; 119 }