[SCOI2007] 修车(费用流 + 差分时间段建图)
problem
luogu-P2053
solution
假設只有一個工作人員。修車順序為 p1,p2,...,pnp_1,p_2,...,p_np1?,p2?,...,pn? 是一個 nnn 的排列。
那么對于第 iii 個被修的車的等待時間應為 Tp1+...TpiT_{p_1}+...T_{p_i}Tp1??+...Tpi??。
總的等待時間則是 Tp1+(Tp1+Tp2)+...+(Tp1+...+Tpn)=Tp1?n+Tp2?(n?1)+...+TpnT_{p_1}+(T_{p_1}+T_{p_2})+...+(T_{p_1}+...+T_{p_n})=T_{p_1}*n+T_{p_2}*(n-1)+...+T_{p_n}Tp1??+(Tp1??+Tp2??)+...+(Tp1??+...+Tpn??)=Tp1???n+Tp2???(n?1)+...+Tpn??。
observation1:\text{observation1}:observation1: 所有車的等待時間就是所有車主的等待時間。
observation2:\text{observation2}:observation2: 越晚修的車對應的修車時間貢獻越少。
從每輛車被等待的時間考慮,每個師傅一次修一輛車,我們按照車輛數將修車師傅拆成 n?mn*mn?m 個點。
車與源點連邊,師傅與匯點連邊,第 iii 輛車和在 kkk 時間段被 jjj 師傅修理連邊,花費 Ti,j?kT_{i,j}*kTi,j??k 表示其修車時間對總時間的貢獻。
跑一個最小費用流即可。
如果有興趣更深入地研究一下此題,可以做 NOI的《美食節》一題 。
code
#include <bits/stdc++.h> using namespace std; #define maxn 1000 struct node { int to, nxt, flow, cost; }E[maxn * maxn]; int head[maxn], dis[maxn], lst[maxn], vis[maxn]; queue < int > q; int m, n, s, t, cnt = -1;void addedge( int u, int v, int w, int c ) {E[++ cnt] = { v, head[u], w, c }, head[u] = cnt;E[++ cnt] = { u, head[v], 0,-c }, head[v] = cnt; }bool SPFA() {memset( dis, 0x3f, sizeof( dis ) );memset( lst, -1, sizeof( lst ) );dis[s] = 0; q.push( s );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( dis[v] > dis[u] + E[i].cost and E[i].flow ) {dis[v] = dis[u] + E[i].cost; lst[v] = i;if( ! vis[v] ) vis[v] = 1, q.push( v );}}}return ~ lst[t]; }int MCMF() {int ans = 0;while( SPFA() ) {int flow = 1e9;for( int i = lst[t];~ i;i = lst[E[i ^ 1].to] ) flow = min( flow, E[i].flow );for( int i = lst[t];~ i;i = lst[E[i ^ 1].to] ) {E[i ^ 1].flow += flow;E[i].flow -= flow;ans += E[i].cost * flow;}}return ans; }int main() {memset( head, -1, sizeof( head ) );scanf( "%d %d", &m, &n );s = 0, t = n * (m + 1) + 1;for( int i = 1;i <= n;i ++ ) {for( int j = 1, ti;j <= m;j ++ ) {scanf( "%d", &ti );for( int k = 1;k <= n;k ++ ) //i車在k時間段被j修理addedge( i + n * m, (k - 1) * m + j, 1e9, ti * k );}}for( int i = 1;i <= n;i ++ ) addedge( s, i + n * m, 1, 0 );for( int i = 1;i <= n * m;i ++ ) addedge( i, t, 1, 0 );printf( "%.2f\n", MCMF() * 1.0 / n );return 0; }總結
以上是生活随笔為你收集整理的[SCOI2007] 修车(费用流 + 差分时间段建图)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 磊科无线路由器怎么设置 设置方法[图文教
- 下一篇: [TJOI2011] 卡片(网络流 +