[CODEVS1917] 深海机器人问题(最小费用最大流)

传送门

 

【问题分析】 

最大费用最大流问题。 

【建模方法】 

把网格中每个位置抽象成网络中一个节点,建立附加源S汇T。 

1、对于每个顶点i,j为i东边或南边相邻的一个节点,连接节点i与节点j一条容量为1,费用为该边价值的有向边。 
2、对于每个顶点i,j为i东边或南边相邻的一个节点,连接节点i与节点j一条容量为无穷大,费用为0的有向边。 
3、从S到每个出发点i连接一条容量为该点出发的机器人数量,费用为0的有向边。 
4、从每个目标点i到T连接一条容量为可以到达该点的机器人数量,费用为0的有向边。 

求最大费用最大流,最大费用流值就采集到的生物标本的最高总价值。 

【建模分析】 

这个问题可以看做是多出发点和目的地的网络运输问题。每条边的价值只能计算一次,容量限制要设为1。同时还将要连接上容量不限,费用为0的重边。由于“多个深海机器人可以在同一时间占据同一位置”,所以不需限制点的流量,直接求费用流即可。

 

吐槽:这出题人语文tm谁教的,输入看了我老半天

 

只需要知道权值不在点,而到了边上,而起点和终点变成了多个,起点和终点都有容量限制。

反而使题目变简单了(因为不再有没有权值的边,而且权值在边上比权值在点上多了一个好处——不用拆点)。

 

——代码

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #define INF 1e9
  6 #define N 1000001
  7 #define min(x, y) ((x) < (y) ? (x) : (y))
  8 
  9 int a, b, n, m, cnt, s, t;
 10 int dis[N], pre[N];
 11 int head[N], to[N << 1], val[N << 1], cost[N << 1], next[N << 1];
 12 bool vis[N];
 13 
 14 inline int read()
 15 {
 16     int x = 0, f = 1;
 17     char ch = getchar();
 18     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
 19     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
 20     return x * f;
 21 }
 22 
 23 inline int hash(int x, int y)
 24 {
 25     return x * m + y;
 26 }
 27 
 28 inline void add2(int x, int y, int z, int c)
 29 {
 30     to[cnt] = y;
 31     val[cnt] = z;
 32     cost[cnt] = c;
 33     next[cnt] = head[x];
 34     head[x] = cnt++;
 35 }
 36 
 37 inline void add(int x, int y, int z, int c)
 38 {
 39     add2(x, y, z, c);
 40     add2(y, x, 0, -c);
 41 }
 42 
 43 inline bool spfa()
 44 {
 45     int i, u, v;
 46     std::queue <int> q;
 47     memset(vis, 0, sizeof(vis));
 48     memset(pre, -1, sizeof(pre));
 49     memset(dis, 127 / 3, sizeof(dis));
 50     q.push(s);
 51     dis[s] = 0;
 52     while(!q.empty())
 53     {
 54         u = q.front(), q.pop();
 55         vis[u] = 0;
 56         for(i = head[u]; i ^ -1; i = next[i])
 57         {
 58             v = to[i];
 59             if(val[i] && dis[v] > dis[u] + cost[i])
 60             {
 61                 dis[v] = dis[u] + cost[i];
 62                 pre[v] = i;
 63                 if(!vis[v])
 64                 {
 65                     q.push(v);
 66                     vis[v] = 1;
 67                 }
 68             }
 69         }
 70     }
 71     return pre[t] ^ -1;
 72 }
 73 
 74 inline int dinic()
 75 {
 76     int i, d, sum = 0;
 77     while(spfa())
 78     {
 79         d = INF;
 80         for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]]) d = min(d, val[i]);
 81         for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]])
 82         {
 83             val[i] -= d;
 84             val[i ^ 1] += d;
 85         }
 86         sum += dis[t] * d;
 87     }
 88     return sum;
 89 }
 90 
 91 int main()
 92 {
 93     int i, j, k, x, y;
 94     a = read();
 95     b = read();
 96     n = read();
 97     m = read();
 98     n++, m++;
 99     s = 0, t = N - 1;
100     memset(head, -1, sizeof(head));
101     for(i = 0; i < n; i++)
102         for(j = 1; j < m; j++)
103         {
104             x = read();
105             add(hash(i, j), hash(i, j + 1), 1, -x);
106             add(hash(i, j), hash(i, j + 1), INF, 0);
107         }
108     for(j = 1; j <= m; j++)
109         for(i = 0; i < n - 1; i++)
110         {
111             x = read();
112             add(hash(i, j), hash(i + 1, j), 1, -x);
113             add(hash(i, j), hash(i + 1, j), INF, 0);
114         }
115     while(a--)
116     {
117         k = read();
118         x = read();
119         y = read();
120         add(s, hash(x, y + 1), k, 0);
121     }
122     while(b--)
123     {
124         k = read();
125         x = read();
126         y = read();
127         add(hash(x, y + 1), t, k, 0);
128     }
129     printf("%d\n", -dinic());
130     return 0;
131 }
View Code

 

posted @ 2017-06-14 15:28  zht467  阅读(195)  评论(0编辑  收藏  举报