POJ 3686 The Windy's(最小费用最大流)

来源:互联网 发布:金牌淘宝客服 编辑:程序博客网 时间:2024/06/03 15:23

点击打开链接

这是挑战上的一道题,不得不说十分的难懂。我看了好久才明白什么意思,当然好像跟挑战上的意思有点区别但是能A就行。

首先,我们知道,这些玩具是可以交给各个工厂去加工的,一个工厂可以加工多个工厂,这里还没什么头绪。

我们来看只有一个工厂的时候,加工n个玩具的总时间就会有T = Z1 + (Z1 + Z2) + .... + (Z1 + Z2 + .... + Zn)

也就是T = n * Z1 + (n - 1) * Z2 + ..... + 1 * Zn

我们可以从上式中看出一些东西,就是玩具i,假设他是在这个工厂里面第k个加工的,那么他就是上面的Zk

我们可以看到,Zk对总时间的贡献就是(n - k + 1) * Zk。

这时候我们就可以把每个工厂给拆点了,拆成了n个点,第k个点代表的是第k个加工。

我们要的是总共的时间最小,那么构图:

一个超级源点连向每个玩具,流量为1,花费为0.

每个工厂拆出来的点连向超级汇点,流量为1,花费为0.

每个玩具i和每个工厂j的第k个加工的点连一条流量为1,花费为(n-k+1)*G[i][j]的边,G[i][j]就是玩具i在j工厂加工的费用。

然后就跑一跑费用流输出即可。

代码如下:

#include<iostream>#include<cstdio>#include<vector>#include<queue>#include<utility>#include<stack>#include<algorithm>#include<cstring>#include<string>#include<cmath>using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 2600;const int maxm = 260000;int n, m;int head[maxn], to[maxm], front[maxm], flow[maxm], cost[maxm], ppp;int dis[maxn], minflow[maxn];bool flag[maxn];pair<int, int> par[maxn];int G[55][55];struct MIN_COST_MAX_FLOW{void init() {memset(head, -1, sizeof(head));ppp = 0;}bool spfa(int s, int e){int u, v;for(int i = 0; i <= e; i++)dis[i] = INF;memset(flag, 0, sizeof(flag));dis[s] = 0;minflow[s] = INF;queue <int> q;q.push(s);while(!q.empty()){u = q.front();q.pop();flag[u] = 0;for(int i = head[u]; ~i; i = front[i]){v = to[i];if(flow[i] && dis[v] > dis[u] + cost[i]){dis[v] = dis[u] + cost[i];par[v] = (make_pair(u, i));minflow[v] = min(minflow[u], flow[i]);if(!flag[v]){flag[v] = 1;q.push(v);}}}}if(dis[e] == INF)return 0;return 1;}int slove(int s, int e){int ans = 0, p;while(spfa(s, e)){p = e;while(p != s){flow[par[p].second] -= minflow[e];flow[par[p].second^1] += minflow[e];p = par[p].first;}ans += dis[e];}return ans;}void add_edge(int u, int v, int f, int c){to[ppp] = v, front[ppp] = head[u], flow[ppp] = f, cost[ppp] = c, head[u] = ppp++;to[ppp] = u, front[ppp] = head[v], flow[ppp] = 0, cost[ppp] = -c, head[v] = ppp++;}}mcmf;int main(){//freopen("poj_in.txt", "r", stdin);int T;cin >> T;while(T--) {mcmf.init();scanf("%d%d", &n, &m);for(int i = 0; i < n; i++) {for(int j = 0; j < m; j++) {scanf("%d", &G[i][j]);}}int s = n + m * n + 1, t = s + 1;for(int i = 0; i < n; i++) {mcmf.add_edge(s, i, 1, 0);}for(int j = 0; j < m; j++) {for(int k = 0; k < n; k++) {mcmf.add_edge(n + j * n + k, t, 1, 0);for(int i = 0; i < n; i++) {mcmf.add_edge(i, n + j * n + k, 1, (n - k) * G[i][j]);}}}int ans = mcmf.slove(s, t);printf("%.6f\n", (double)(ans) / n);}return 0;}


原创粉丝点击