【BZOJ】1070: [SCOI2007]修车
1070: [SCOI2007]修車
Description
同 一時刻有N位車主帶著他們的愛車來到了汽車維修中心。維修中心共有M位技術人員,不同的技術人員對不同的車進行維修所用的時間是不同的。現在需要安排這M 位技術人員所維修的車及順序,使得顧客平均等待的時間最小。 說明:顧客的等待時間是指從他把車送至維修中心到維修完畢所用的時間。
Input
第一行有兩個m,n,表示技術人員數與顧客數。 接下來n行,每行m個整數。第i+1行第j個數表示第j位技術人員維修第i輛車需要用的時間T。
Output
最小平均等待時間,答案精確到小數點后2位。
Sample Input
2 23 2
1 4
Sample Output
1.50HINT
數據范圍: (2<=M<=9,1<=N<=60), (1<=T<=1000)
思路:開始以為排序之后模擬貪心,但是車的數量太多...每次對于一個工人來說,并不是直接按照他修理車的最短時間給他分配車的,還要看里面各種..修車時間差與等待總時間等因素;所以要用到網絡流構圖,讓計算機不斷的調整選擇方案(增廣路模擬);即最小費用最大流問題;
暴力構圖:每個工人可能修理的車的數量即為車的數量,并且每次修理車的時間并不只是輸入的時間,因為對于同一個工人來說其前面修理的車的時間會累加到后面修車的時間里面;但是一般這樣前面對后面產生的次數影響,并不是對當前的車去看它前面修了哪些車,然后把這些車的總時間加上自己的時間代價的,因為這樣還要不斷記錄與修改修車的順序。。與其后面每次來找前面的麻煩。。還不如前面修理的時候直接計算出對后面的影響~~ 即該車是同一個工人倒數第k次修的,那么這輛車的總代價就是k*time[i][j];這樣就有了暴力拆點的依據了~~
暴力拆點:把每個工人拆成m個點,第k個點表示是倒數第k次修的該車,至于該車就修改每輛車與n*m個點連邊,邊的容量為1,表示只修一次。費用為time[i]][j]*k;至于與超級源點和匯點連邊時,cap為1,但是費用記得要記為0;這樣直接跑最大流即可;
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; #define MS0(a) memset((a),0,sizeof(a)) #define MSi(a) memset((a),0x3f,sizeof(a)) #define MS1(a) memset((a),-1,sizeof(a)) #define inf 0x3f3f3f3f const int T = 1001; const int M = 50000; const int N = 1007; int tot = 1,head[N]; struct edge{int from,to,Next,cap,cost; }e[M<<1]; void ins(int u,int v,int cap,int cost) {e[++tot].Next = head[u];// tot從2開始,之后增廣邊還是可以異或~~并且head并不需要設為-1.e[tot].from = u, e[tot].to = v;e[tot].cap = cap; e[tot].cost = cost;head[u] = tot; } void insert(int u,int v,int cap,int cost)//把cap當成費用;之后增廣路中只是改變flow; {ins(u,v,cap,cost);ins(v,u,0,-cost); } int t[61][10],dis[N],vis[N],p[N]; queue<int> que; int spfa() {MSi(dis);que.push(0);p[0] = 0;dis[0] = 0;while(!que.empty()){int u = que.front();que.pop();vis[u] = 0;for(int d = head[u];d ;d = e[d].Next){int v = e[d].to; if(e[d].cap && dis[v] > dis[u] + e[d].cost){ dis[v] = dis[u]+e[d].cost;p[v] = d;if(!vis[v]){que.push(v);vis[v] = 1;}}}} if(dis[T] == inf) return 0;return 1; } int ans; int mcf() {int v = inf;for(int d = p[T];d;d = p[e[d].from])v = min(v,e[d].cap);for(int d = p[T];d;d = p[e[d].from]){e[d].cap -= v; e[d^1].cap += v;ans += e[d].cost;} } int main() {int n,m;scanf("%d%d",&n,&m);for(int i = 1;i <= m;i++)for(int j = 1;j <= n;j++)scanf("%d",&t[i][j]);for(int i = 1;i <= n;i++)for(int j = 1;j <= m;j++)insert(0,(i-1)*m+j,1,0);for(int i = n*m+1;i <= n*m+m;i++)insert(i,T,1,0);for(int i = 1;i <= n;i++)for(int j = 1;j <= m;j++)//第i個工人修的倒數第j輛車;for(int k = 1;k <= m;k++)insert((i-1)*m+j,n*m+k,1,t[k][i]*j);while(spfa()) mcf();printf("%.2f",1.*ans/m); }?
轉載于:https://www.cnblogs.com/hxer/p/5259009.html
總結
以上是生活随笔為你收集整理的【BZOJ】1070: [SCOI2007]修车的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单点登录认证方案思路,求好思路回复
- 下一篇: Java与C/C++的比较(转)