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\n", MFMC(S, T) / n); 76 } 77 return 0; 78 }