题目大意:
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
思路分析:
①:设立一个源点,连向每一辆车,容量为1,费用为0;
②:让每辆车i连向技术人员j,把技术人员拆成n部分,每条边容量为1,费用为(n-k+1)*time[i][j],(k代表一个技术人员被拆成的第几个点,也就代表当前这辆车被这个维修人员第几个修);
③:让n*m个技术人员连向汇点,容量为1,费用为0;
这道题要注意的是顾客的等待时间不光是自己维修所需的时间,还有等待别人维修的时间(用一同一位技术人员的),刚开始是这样建图的,设立一个源点,连向n辆车,再用n两车连向m个技术人员,然后每次找到一个能扩增的流,就在此条路径车连向汇点的边加上此次的花费,我想这样就相当于加上等待别人维修的时间了,可是这样想是不对的,我想到了一个这样的样例 2 2---3 2---8 4,两辆车,两位技术人员,如果按照我此时的做法,那么顾客的平均等待时间就是4.00,第二位技术人员先修理第一辆车,第二辆车等着第一辆修完了再修理,而实际上,只需要3.50,第一位技术人员修理第一辆车,同时第二位技术人员修理第二辆车。。。而这时候应该怎么做呢,(此时参考了别人的思想。。。)我们可以把每个技术人员分成n个人,代表一个人可以修n辆车,对于一辆车i,可以被一位技术人员j,第一个修,第二个修。。。第n个修,那么如果它被修,别人如果也用这个技术人员,就需要等待,等待的时间也就是(n-k+1)*time[i][j] (k代表第几个修,后面也就有n-k个人等待,要算上自己的时间啊。。) 。于是建立这样一个图,设立一个源点s,连向每一辆车,容量为1,费用为0,再把每辆车连向每位技术人员(每个有n个点,对应第几个修,容量为1,费用为上面的式子),最后,再让m*n个技术人员连向汇点,容量为1,费用为0;
说一个样例,正是通过这个样例让我突然理解为什么我们在加边的时候,反向边的费用为什么是-cost:
在第一次循环的时候,走的路线是s-->1-->6-->t 费用是2,也就是第一辆车被第二个技术人员修理,其实这不是我们理想的,我们理想的是,第一辆车被第一个技术人员修理,这样才能同时第二辆车被第二个技术人员修理,别着急,往下看,第二次循环的时候,0-->1,6-->t 这两条路走过了不能走(图中画x),我们先是从s-->2,2-->6,然后我们就沿着6-->1(原本容量为0,费用为-2,在走过1-->6之后,容量也就为1,费用为0) 然后dis[1]=dis[6]+edge[].cost=4+(-2)=2,继而,又从1-->4->t,费用为5,看到这里,有没有发现什么,是不是最后的结果就好像1-->6这条边没有被走过,来回走了两遍,得用一正一负抵消了,然后好像走的就是s-->1-->4-->t,s-->2-->6-->t,这和我们理想的就是一样的了,太神奇了。。。。
由于不会画图,就只能在纸上画图拍照了,嘻嘻 ,这就是我对这道题的全部理解了,希望看到我这篇文章的人不要笑啊。。。嘻嘻嘻
代码实现:
zkw:600ms
#include<cstdio>
#include<cstring>
#include<iostream>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int N=700;
const int M=74320;
const int INF=0x3f3f3f3f;
int n,m,s,t,top,head[N],vis[N],tim[65][15],cost,ans;
struct Edge{
int to,next,flow,cost;
Edge(int _to=0,int _next=0,int _flow=0,int _cost=0):to(_to),next(_next),flow(_flow),cost(_cost){}
}edge[M];
void Addedge(int from,int to,int flow,int cost){
edge[top]=Edge(to,head[from],flow,cost);
head[from]=top++;
edge[top]=Edge(from,head[to],0,-cost);
head[to]=top++;
}
int aug(int u,int f){
if(u==t){
ans+=cost*f;
return f;
}
vis[u]=1;
int tmp=f;
for(int i=head[u];i!=-1;i=edge[i].next){
if(edge[i].flow&&!edge[i].cost&&!vis[edge[i].to]){
int delta=aug(edge[i].to,Min(tmp,edge[i].flow));
edge[i].flow-=delta;
edge[i^1].flow+=delta;
tmp-=delta;
if(!tmp) return f;
}
}
return f-tmp;
}
bool modlabel(){
int delta=INF;
for(int u=s;u<=t;u++){
if(vis[u]){
for(int i=head[u];i!=-1;i=edge[i].next)
if(edge[i].flow&&!vis[edge[i].to]&&edge[i].cost<delta) delta=edge[i].cost;
}
}
if(delta==INF) return 0;
for(int u=s;u<=t;++u){
if(vis[u]){
for(int i=head[u];i!=-1;i=edge[i].next)
edge[i].cost-=delta,edge[i^1].cost+=delta;
}
}
cost+=delta;
return 1;
}
void costflow(){
do{
do{
memset(vis,0,sizeof(vis));
}while(aug(s,INF));
}while(modlabel());
}
int main(){
while(~scanf("%d%d",&m,&n)){
memset(head,-1,sizeof(head));
top=ans=cost=0;
s=0,t=n*m+n+1;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) scanf("%d",&tim[i][j]);
for(int i=1;i<=n;++i) Addedge(s,i,1,0);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
for(int k=1;k<=n;++k){
Addedge(i,j*n+k,1,k*tim[i][j]);
}
}
}
for(int i=1;i<=m;++i)
for(int j=1;j<=n;++j) Addedge(i*n+j,t,1,0);
costflow();
double res=ans*(1.0)/n;
printf("%.2lf\n",res);
}
}
spfa:784ms
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int N=700;
const int M=74320;
const int INF=0x3f3f3f3f;
int n,m,s,t,top,head[N],vis[N],sum_cost,ans,dis[N],pre[N],minflow[N],path[N],tim[65][15];
struct Edge{
int to,next,flow,cost;
Edge(int _to=0,int _next=0,int _flow=0,int _cost=0):to(_to),next(_next),flow(_flow),cost(_cost){}
}edge[M];
void Addedge(int from,int to,int flow,int cost){
edge[top]=Edge(to,head[from],flow,cost);
head[from]=top++;
edge[top]=Edge(from,head[to],0,-cost);
head[to]=top++;
}
int Spfa(){
queue<int> q;
memset(dis,0x3f,sizeof(dis));
memset(minflow,0x3f,sizeof(minflow));
memset(pre,-1,sizeof(pre));
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i+1;i=edge[i].next){
if(edge[i].flow&&dis[edge[i].to]>dis[u]+edge[i].cost){
dis[edge[i].to]=dis[u]+edge[i].cost;
pre[edge[i].to]=u;
path[edge[i].to]=i;
minflow[edge[i].to]=Min(minflow[u],edge[i].flow);
if(!vis[edge[i].to]){
vis[edge[i].to]=1;
q.push(edge[i].to);
}
}
}
}
if(dis[t]==INF) return 0;
sum_cost+=minflow[t]*dis[t];
int u=t;
while(u!=s){
edge[path[u]].flow-=minflow[t];
edge[path[u]^1].flow+=minflow[t];
u=pre[u];
}
return 1;
}
int main(){
while(~scanf("%d%d",&m,&n)){
memset(head,-1,sizeof(head));
top=sum_cost=0;
s=0,t=n*m+n+1;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) scanf("%d",&tim[i][j]);
for(int i=1;i<=n;++i) Addedge(s,i,1,0);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
for(int k=1;k<=n;++k){
Addedge(i,j*n+k,1,(n-k+1)*tim[i][j]);
}
}
}
for(int i=1;i<=m;++i)
for(int j=1;j<=n;++j) Addedge(i*n+j,t,1,0);
while(Spfa());
double res=sum_cost*(1.0)/n;
printf("%.2lf\n",res);
}
}