题面
<center> [SCOI2007]修车<center>
<center>时间限制:1秒 内存限制:128MB<center>
题目描述
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
输入
第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T。
输出
最小平均等待时间,答案精确到小数点后2位。
样例输入
2 2
3 2
1 4
样例输出
1.50
提示
数据范围: (2<=M<=9,1<=N<=60)
思路
题解
第一感觉,是用DP做,用DP想了半天发觉不对。搜了题解才知道,是用最大流的最小费用做。 地地道道的一道模板题,在网上搜到了模板。最主要的是:如何建图。首先建立源点S和汇点T,N辆车和M个工人都作为中间的节点,其中每位工人分为N个,代表服务车的顺序。将S与N辆车相连,N*M个工人节点与T相连,流均为1,费用为0,再将N辆车与N*M个工人节点相连,流也为1,费用计算方法为:k*ti,即第i辆车由第j个工人修理的时间*后面需要的车辆数(意思是:假如第j个工人修理第i辆车的次序为x,那么还有(n-x)辆车也需要等待ti的时间)。建图完毕后,调用模板进行计算即可得出总的等待时间,除以n就可以平均等待时间。
源码
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#define inf 0x7fffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define T 1001
using namespace std;
const int MAXN=1e6+5;
int n,m,ans,cnt=0,st,ed,t[65][10];
int head,tail;
int list[1005],pre[1005],vi[1005],first[1005],c[1005];
bool v[1005];
typedef struct {//定义节点类型
int from,to,next,f,w,other;
}Node;
Node e[MAXN];
void insert(int u,int v,int f,int w){//插入节点(包括正向节点和反向节点)
int kx,ky;
cnt++;
kx=cnt;
e[cnt].from=u;e[cnt].to=v;e[cnt].f=f;e[cnt].w=w;
e[cnt].next=first[u];first[u]=cnt;
cnt++;ky=cnt;
e[cnt].from=v;e[cnt].to=u;e[cnt].f=0;e[cnt].w=-w;
e[cnt].next=first[v];first[v]=cnt;
e[kx].other=ky;e[ky].other=kx;
}
bool spfa(){//求解算法
mem(c,0);c[st]=999999999;
//memset(v,false,sizeof(v));
mem(v,false);
v[st]=true;
mem(vi,0x3F);vi[st]=0;
list[1]=st;head=1;tail=2;pre[st]=0;
while(head!=tail){
int x=list[head];
for(int k=first[x];k>0;k=e[k].next){
int y=e[k].to;
if(e[k].f>0&&vi[y]>vi[x]+e[k].w){
vi[y]=vi[x]+e[k].w;
c[y]=min(c[x],e[k].f);
pre[y]=k;
if(v[y]==false){
v[y]=true;
list[tail++]=y;
if(tail==ed+1)tail=1;
}
}
}
head++;if(head==ed+1)head=1;
v[x]=false;
}
if(vi[ed]>999999999)return false;
ans+=vi[ed]*c[ed];
int x=ed;
while(x!=st){
int k=pre[x];
e[k].f-=c[ed];e[e[k].other].f+=c[ed];
x=e[k].from;
}
return true;
}
int main(){
scanf("%d%d",&m,&n);
st=n*m+n+1;ed=n*m+n+2;
cnt=0;mem(first,0);
int i,j,k,p;
for(i=1;i<=n;i++)
for( j=1;j<=m;j++){
scanf("%d",&t[i][j]);//输入第i辆车由第j个工人修理所需时间
}
for(i=1;i<=n;i++) insert(st,i,1,0);//将源点S和N个车节点相连
p=m*n;
for(j=1;j<=p;j++) insert(n+j,ed,1,0);//将N*M个工人节点与汇点T相连
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
for(k=1;k<=n;k++){
insert(i,j*n+k,1,t[i][j]*(n-k+1));//将N个车节点与N*M个工人节点相连
}
}
}
ans=0;
while(spfa());//求解
printf("%.2lf\n",double(ans)/double(n));
return 0;
}