P2053 [SCOI2007]修車 費用流
阿新 • • 發佈:2019-03-03
bool bits pri span hang 題解 ffffff col fin
$ \color{#0066ff}{ 題目描述 }$
同一時刻有N位車主帶著他們的愛車來到了汽車維修中心。維修中心共有M位技術人員,不同的技術人員對不同的車進行維修所用的時間是不同的。現在需要安排這M位技術人員所維修的車及順序,使得顧客平均等待的時間最小。
說明:顧客的等待時間是指從他把車送至維修中心到維修完畢所用的時間。
\(\color{#0066ff}{輸入格式}\)
第一行有兩個數M,N,表示技術人員數與顧客數。
接下來n行,每行m個整數。第i+1行第j個數表示第j位技術人員維修第i輛車需要用的時間T。
\(\color{#0066ff}{輸出格式}\)
最小平均等待時間,答案精確到小數點後2位。
\(\color{#0066ff}{輸入樣例}\)
2 2
3 2
1 4
\(\color{#0066ff}{輸出樣例}\)
1.50
\(\color{#0066ff}{數據範圍與提示}\)
(2<=M<=9,1<=N<=60), (1<=T<=1000)
\(\color{#0066ff}{題解}\)
這種對應關系還有數據範圍,顯然就是費用流了
現在的問題是怎麽建邊
發現,每輛車的等待時間跟前面修車人所修的車有關
假設某人修了10輛車
那麽他修第一輛的時候,後面9人都等了這個時間,也就是貢獻+=9倍的這個時間
因此我們單獨考慮這個人修的每一輛車對時間的貢獻
把每個人都拆成n個點
對於一個人的第k個點,連向它的車代表他倒數第k次修它
也就是連T*k的邊權,倒數第k次修它,那麽後面k輛車就會產生這麽多貢獻
跑一遍費用流即可(zkw大法好)
// luogu-judger-enable-o2 #include<bits/stdc++.h> #define LL long long LL in() { char ch; LL x = 0, f = 1; while(!isdigit(ch = getchar()))(ch == '-') && (f = -f); for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48)); return x * f; } const int maxn = 1e5 + 10; const int inf = 0x7fffffff; struct node { int to, can, dis; node *nxt, *rev; node(int to = 0, int can = 0, int dis = 0, node *nxt = NULL): to(to), can(can), dis(dis), nxt(nxt) { rev = NULL; } }; node *head[maxn], *cur[maxn]; bool vis[maxn]; int n, m, s, t; int dis[maxn]; void add(int from, int to, int can, int dis) { head[from] = new node(to, can, dis, head[from]); } void link(int from, int to, int can, int dis) { add(from, to, can, dis); add(to, from, 0, -dis); head[from]->rev = head[to]; head[to]->rev = head[from]; } bool spfa() { std::queue<int> q; for(int i = s; i <= t; i++) dis[i] = inf, vis[i] = false; q.push(t); dis[t] = 0; while(!q.empty()) { int tp = q.front(); q.pop(); vis[tp] = false; for(node *i = head[tp]; i; i = i->nxt) { if(dis[i->to] > dis[tp] - i->dis && i->rev->can) { dis[i->to] = dis[tp] - i->dis; if(!vis[i->to]) { q.push(i->to); vis[i->to] = true; } } } } return dis[s] != inf; } int dfs(int x, int change) { if(x == t || !change) return change; int flow = 0, ls; vis[x] = true; for(node *i = head[x]; i; i = i->nxt) { if(!vis[i->to] && dis[i->to] == dis[x] - i->dis && (ls = dfs(i->to, std::min(change, i->can)))) { flow += ls; change -= ls; i->can -= ls; i->rev->can += ls; if(!change) break; } } return flow; } int zkw() { int cost = 0; while(spfa()) { vis[t] = true; while(vis[t]) { for(int i = s; i <= t; i++) vis[i] = false; cost += dis[s] * dfs(s, inf); } } return cost; } int main() { m = in(), n = in(), s = 0, t = m * n + n + 1; for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) link(s, (i - 1) * n + j, 1, 0); for(int i = 1; i <= n; i++) link(m * n + i, t, 1, 0); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { int x = in(); for(int k = 1; k <= n; k++) link((j - 1) * n + k, n * m + i, 1, k * x); } printf("%.2f\n", (double)zkw() / n); return 0; }
P2053 [SCOI2007]修車 費用流