1070: [SCOI2007]修车
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 5655 Solved: 2383
[ Submit][ Status][ Discuss]
Description
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同
的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最
小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
Input
第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人
员维修第i辆车需要用的时间T。
Output
最小平均等待时间,答案精确到小数点后2位。
Sample Input
3 2
1 4
Sample Output
HINT
数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)
题目思路:
首先分析问题,最终状态应该是把来修车的n个人分成m队,也就是每个修车师傅面前排一队人,其中这个队里的第k个人等待时间是k*这个人在该技术工人这里修车的时间T;
那么,也就是说把这n个人分配到m个队中的某个位置上,每个人只分配一次,每个位置只有一个人。
因此,可以用网络流来解决。图中共有1个源点,1个汇点,n个节点代表n个人(人节点 ),n*m个节点代表每个队列中的每个位置(位置节点)。从源点向每个人节点连一条容量为1,费用是0的边;从每个人节点向每个位置节点连一条边,容量为1,费用是这个人站在这个队列的这个位置时的花费;每个位置节点向汇点连一条容量是1,费用是0的边。跑一遍源点到汇点的最小费用最大流得到答案。
看了一下status,速度差距明显,查了一下网上题解的做法,认为有必要学一下zkw费用流。
#pragma warning(disable:4786)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#include<bitset>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-6;
const int maxn = 700;
int c[65][15];
struct Edge
{
int from , to , cap , flow , cost;
};
struct MCMF
{
int n, m ,s , t;
vector<Edge>edges;
vector<int>G[maxn];
int d[maxn] , p[maxn] , a[maxn] , inq[maxn];
void init(int n){
this -> n = n;
for(int i = 0 ; i <= n ; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from , int to , int cap , int cost){
Edge e1 = {from , to , cap , 0 , cost};
Edge e2 = {to , from , 0 , 0 , -cost};
edges.push_back(e1);
edges.push_back(e2);
int m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
bool BellmanFord(int s , int t , int & flow , LL & cost){
mem(d , INF);
d[s] = 0; p[s] = 0; a[s] = INF;
mem(inq , 0); inq[s] = 1;
queue<int>Q;
Q.push(s);
while(!Q.empty()){
int x = Q.front(); Q.pop();
inq[x] = 0;
for(int i = 0 ; i < G[x].size() ; i++){
Edge & e = edges[G[x][i]];
if(e.cap > e.flow && d[e.to] > d[x] + e.cost){
d[e.to] = d[x] + e.cost;
p[e.to] = G[x][i];
a[e.to] = min(a[x] , e.cap - e.flow);
if(!inq[e.to]){
Q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if(d[t] == INF) return false;
flow += a[t];
cost += (LL)a[t] * (LL)d[t];
int u = t;
while(u != s){
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
u = edges[p[u]].from;
}
return true;
}
LL Mincost(int s , int t , int & flow){
flow = 0;
LL cost = 0;
while(BellmanFord(s , t , flow , cost)) ;
return cost;
}
}g;
int main()
{
int n , m;
while(scanf("%d %d" , &m , &n) != EOF){
for(int i = 1 ; i <= n ; i++){
for(int j = 1 ; j <= m ; j++){
scanf("%d" , &c[i][j]);
}
}
g.init(2 + n * m + n);
int source = 1 , sink = 2 + n * m + n;
for(int i = 1 ; i <= n; i++){
g.AddEdge(source , 1 + i , 1 , 0);
for(int j = 1 ; j <= m ; j++){
for(int k = 1 ; k <= n; k++){
g.AddEdge(i + 1 , 1 + n + n * (j - 1) + k , 1 , k * c[i][j]);
}
}
}
for(int j = 1 ; j <= m ; j++){
for(int k = 1 ; k <= n; k++){
g.AddEdge(1 + n + n * (j - 1) + k , sink , 1 , 0);
}
}
int flow ;
double ans = (double)g.Mincost(source , sink , flow);
ans = ans / n;
printf("%.2lf\n" , ans);
}
return 0;
}