POJ 3686 The Windy's(思維+費用流好題)
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 5362 | Accepted: 2249 |
Description
The Windy‘s is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys. The manager knows that every order will take different amount of hours in different workshops. More precisely, the i
The manager wants to minimize the average of the finishing time of the N
Input
The first line of input is the number of test case. The first line of each test case contains two integers, N and M (1 ≤ N,M ≤ 50).
The next N lines each contain M integers, describing the matrix Zij (1 ≤ Zij ≤ 100,000) There is a blank line before each test case.
Output
For each test case output the answer on a single line. The result should be rounded to six decimal places.
Sample Input
3 3 4 100 100 100 1 99 99 99 1 98 98 98 1 3 4 1 100 100 100 99 1 99 99 98 98 1 98 3 4 1 100 100 100 1 99 99 99 98 1 98 98
Sample Output
2.000000 1.000000 1.333333
題目連接:POJ 3686
刷白書的網絡流問題看到的,跟某一道導彈發射的問題很像,但是這題不同工廠對不同的物品都有不同的加工時間,按加工次序拆點是很容易想到, 但這樣一想有一個問題,比如我把物品連到工場2的第二次加工時間點,那我這條邊流量是1,費用是多少根本不知道,因為我不知道工廠2第一次加工的那條邊費用是多少,即不知道當前物品加工時等待了多久,因此需要換一種思路。
比如有三個物品a,b,c都在同一個工廠加工,那麽時間可以這麽寫:ta+ta+tb+ta+tb+tc=3ta+2tb+1tc,顯然最先加工的是a,其次是b,最後是c,可以發現物品前面的系數的最大值就是在工廠加工的總物品數,那麽這題實際上就是一個系數分配問題,那麽建圖就好辦了, 費用就是加工次序*加工時間,由於流量是1,確實解決了同一時間只能加工一個物品的問題,但可能又會想,那我的某一個物品萬一在工廠1的第k次序加工,但是實際上工廠1前k-1次機會都沒有用過,這豈不是非常浪費嗎?實際上由於用的是SPFA最短路增廣,求解過程就是求出了總時間最優的情況,不會出現前面空著的加工次序問題,如果有空著的加工次序,那麽SPFA一定會找到並把這條邊松弛算進網絡流中
代碼:
#include <stdio.h> #include <iostream> #include <algorithm> #include <cstdlib> #include <sstream> #include <numeric> #include <cstring> #include <bitset> #include <string> #include <deque> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 55; const int MAXV = N + N * N; const int MAXE = N + N * N + N * N * N; struct edge { int to, nxt, cap, cost; edge() {} edge(int _to, int _nxt, int _cap, int _cost): to(_to), nxt(_nxt), cap(_cap), cost(_cost) {} }; edge E[MAXE << 1]; int head[MAXV], tot; int vis[MAXV], pre[MAXV], path[MAXV], d[MAXV]; int Z[N][N]; int mc, mf; void init() { CLR(head, -1); tot = 0; mc = mf = 0; } inline void add(int s, int t, int cap, int cost) { E[tot] = edge(t, head[s], cap, cost); head[s] = tot++; E[tot] = edge(s, head[t], 0, -cost); head[t] = tot++; } int spfa(int s, int t) { queue<int>Q; Q.push(s); CLR(d, INF); CLR(vis, 0); d[s] = 0; vis[s] = 1; while (!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = 0; for (int i = head[u]; ~i; i = E[i].nxt) { int v = E[i].to; if (d[v] > d[u] + E[i].cost && E[i].cap > 0) { d[v] = d[u] + E[i].cost; pre[v] = u; path[v] = i; if (!vis[v]) { vis[v] = 1; Q.push(v); } } } } return d[t] != INF; } void MCMF(int s, int t) { int i; while (spfa(s, t)) { int Min = INF; for (i = t; i != s; i = pre[i]) Min = min(Min, E[path[i]].cap); for (i = t; i != s; i = pre[i]) { E[path[i]].cap -= Min; E[path[i] ^ 1].cap += Min; } mf += Min; mc += Min * d[t]; } } int main(void) { int tcase, n, m, i, j, k; scanf("%d", &tcase); while (tcase--) { init(); scanf("%d%d", &n, &m); for (i = 1; i <= n; ++i) for (j = 1; j <= m; ++j) scanf("%d", &Z[i][j]); int S = 0, T = n + n * m + 1; for (i = 1; i <= n; ++i) //n源點到需加工物品 add(S, i, 1, 0); for (i = n + 1; i <= n + n * m; ++i) //n*m加工時間點到匯點 add(i, T, 1, 0); for (i = 1; i <= n; ++i) { for (j = 1; j <= m; ++j) { for (k = 1; k <= n; ++k)//遍歷不同時間點 { int id = j * n + k; add(i, id, 1, k * Z[i][j]); //n*m*n } } } MCMF(S, T); printf("%.6f\n", mc * 1.0 / n); } return 0; }
POJ 3686 The Windy's(思維+費用流好題)