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 }

 

posted @ 2018-05-24 20:08  NotNight  阅读(106)  评论(0编辑  收藏  举报