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


    http://poj.org/problem?id=3686

    题意:给出n个玩具和m个工厂,每个工厂加工每个玩具有一个时间,问要加工完这n个玩具最少需要等待的平均时间。例如加工1号玩具时间为t1,加工2号玩具时间为t2。那么先加工玩具1再加工玩具2花费的时间是t1+(t1+t2),先加工玩具2在加工玩具1花费的时间是t2+(t1+t2)。

    思路:假设所有玩具在一个工厂加工,那么等待的时间是

    t1 + (t1 + t2) + (t1 + t2 + t3) + ……

    = t1 * n + t2 * (n-1) + t3 * (n-2) + ……

    那么可以把每个工厂能够加工n个玩具转化成有n个工厂每个只能够加工一个玩具,即每个工厂被划分成权值w为1,2,3,……,n的工厂,然后每个工厂制造某个玩具花费的时间为权值*本来需要的时间。

    建图即:

    源点向每个玩具连流量为1,费用为0的边,

    每个玩具向每个工厂连流量为1,费用为w(w为工厂的权值)*cost的边,

    每个工厂向源点连流量为1,费用为0的边。

    然后跑一遍最小费用最大流,最后把答案除以玩具数就是最终答案。

    这个建图思维很厉害。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <queue>
     5 using namespace std;
     6 #define N 2666
     7 #define INF 0x3f3f3f3f
     8 struct Edge {
     9     int u, v, nxt, cap, cost;
    10     Edge () {}
    11     Edge (int u, int v, int nxt, int cap, int cost) : u(u), v(v), nxt(nxt), cap(cap), cost(cost) {}
    12 } edge[N*N];
    13 int n, m, mp[55][55], head[N], tot, pre[N], dis[N], vis[N], S, T;
    14 
    15 void Add(int u, int v, int cap, int cost) {
    16     edge[tot] = Edge(u, v, head[u], cap, cost); head[u] = tot++;
    17     edge[tot] = Edge(v, u, head[v], 0, -cost); head[v] = tot++;
    18 }
    19 
    20 bool SPFA(int S, int T) {
    21     queue<int> que; que.push(S);
    22     memset(dis, INF, sizeof(dis));
    23     memset(vis, 0, sizeof(vis));
    24     dis[S] = 0, vis[S] = 1;
    25     while(!que.empty()) {
    26         int u = que.front(); que.pop();
    27         vis[u] = 0; // 忘了这句.WA了N久
    28         for(int i = head[u]; ~i; i = edge[i].nxt) {
    29             int v = edge[i].v, cap = edge[i].cap, cost = edge[i].cost;
    30             if(dis[v] > dis[u] + cost && cap > 0) {
    31                 dis[v] = dis[u] + cost; pre[v] = i;
    32                 if(!vis[v]) vis[v] = 1, que.push(v);
    33             }
    34         }
    35     }
    36     return dis[T] < INF;
    37 }
    38 
    39 double MFMC(int S, int T) {
    40     int u, flow;
    41     double ans = 0;
    42     while(SPFA(S, T)) {
    43         u = T, flow = INF;
    44         while(u != S) {
    45             if(flow > edge[pre[u]].cap) flow = edge[pre[u]].cap;
    46             u = edge[pre[u]].u;
    47         } u = T;
    48         while(u != S) {
    49             edge[pre[u]].cap -= flow, edge[pre[u]^1].cap += flow;
    50             ans += edge[pre[u]].cost * flow;
    51             u = edge[pre[u]].u;
    52         }
    53     }
    54     return ans;
    55 }
    56 
    57 int main() {
    58     int t; scanf("%d", &t);
    59     while(t--) {
    60         scanf("%d%d", &n, &m);
    61         for(int i = 1; i <= n; i++)
    62             for(int j = 1; j <= m; j++)
    63                 scanf("%d", &mp[i][j]);
    64         S = 0, T = n * m + n + 1;
    65         memset(head, -1, sizeof(head)); tot = 0;
    66         for(int i = 1; i <= n; i++) {
    67             Add(S, i, 1, 0);
    68             for(int j = 1; j <= m; j++) {
    69                 Add(j * n + i, T, 1, 0);
    70                 for(int k = 1; k <= n; k++) {
    71                     Add(i, j * n + k, 1, k * mp[i][j]);
    72                 }
    73             }
    74         }
    75         printf("%.6f
    ", MFMC(S, T) / n);
    76     }
    77     return 0;
    78 }
  • 相关阅读:
    python学习之函数基础
    Java并发编程之支持并发的list集合你知道吗
    Java并发编程之CAS第三篇-CAS的缺点及解决办法
    Java并发编程之CAS二源码追根溯源
    Java并发编程之CAS第一篇-什么是CAS
    Java并发编程之验证volatile指令重排-理论篇
    【免费百度网盘不限速】爱奇艺万能联播 百度网盘不限速的方法
    Java并发编程之验证volatile不能保证原子性
    Java并发编程之验证volatile的可见性
    Java并发编程学习前期知识下篇
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6751675.html
Copyright © 2020-2023  润新知