【bzoj 1070】 修车 【SCOI2007】

Description

  同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同
的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最
小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。

Input

  第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人
员维修第i辆车需要用的时间T。

Output

  最小平均等待时间,答案精确到小数点后2位。

Sample Input

2 2
3 2
1 4

Sample Output

1.50

HINT

数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)

对于这道题,可以设置超级源和超级汇,将技术人员U_{i}拆为U_{i1}~U_{in},表示第i个技术人员倒数第1~n个修车,分别与超级汇连接一条权值为1,费用为0的边,再向每个客户连接一条权值为1,费用为kT_{ij}(k为倒数第几个修车)边,最后从超级源向每个客户连一条权值为1,费用为0的边,在这张图上跑一遍费用流就可以了,下面是程序:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int N=700,INF=0x3f3f3f3f;
struct queue{
	int l,r,a[N];
	void clear(){
		l=0,r=1;
	}
	bool empty(){
		return l+1==r;
	}
	void push(int x){
		a[r]=x;
		r=(r+1)%N;
	}
	void pop(){
		l=(l+1)%N;
	}
	int front(){
		return a[(l+1)%N];
	}
}q;
struct node{
	int u,e;
}last[N];
struct edge{
	int v,w,c,next;
}e[N*200];
int head[N],dis[N],s=0,t=N-1,k;
bool vis[N];
void add(int u,int v,int w,int c){
	e[k]=(edge){v,w,c,head[u]};
	head[u]=k++;
	e[k]=(edge){u,0,-c,head[v]};
	head[v]=k++;
}
int SPFA(){
	q.clear();
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	q.push(s);
	vis[s]=1;
	int u,i;
	while(!q.empty()){
		u=q.front();
		q.pop();
		vis[u]=0;
		for(i=head[u];i!=-1;i=e[i].next){
			if(e[i].w&&dis[u]+e[i].c<dis[e[i].v]){
				last[e[i].v]=(node){u,i};
				dis[e[i].v]=dis[u]+e[i].c;
				if(!vis[e[i].v]){
					vis[e[i].v]=1;
					q.push(e[i].v);
				}
			}
		}
	}
	return dis[t];
}
int work(){
	int i,f=INF;
	for(i=t;i;i=last[i].u){
		f=min(f,e[last[i].e].w);
	}
	for(i=t;i;i=last[i].u){
		e[last[i].e].w-=f;
		e[last[i].e^1].w+=f;
	}
	return f;
}
int ek(){
	int c,ans=0;
	while((c=SPFA())!=INF){
		ans+=c*work();
	}
	return ans;
}
int main(){
	int n,m,i,j,k,x;
	scanf("%d%d",&m,&n);
	memset(head,-1,sizeof(head));
	t=n*m+n+1;
	for(i=1;i<=n;i++){
		add(s,i,1,0);
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			scanf("%d",&x);
			for(k=1;k<=n;k++){
				add(i,j*n+k,1,k*x);
			}
		}
	}
	for(i=n+1;i<=m*n+n;i++){
		add(i,t,1,0);
	}
	printf("%.2lf\n",ek()*1.0/n);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/TLECOCE/article/details/81349668
今日推荐