bzoj 1070: [SCOI2007]修车

1070: [SCOI2007]修车

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 4032   Solved: 1643
[ Submit][ Status][ Discuss]

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)

Source


题解:费用流神题,真正困扰了一晚上啊。
刚开始时想法就跑偏了,想着用后来修的车给前面修的车补流,但是搞来搞去发现貌似不对,然后就弃疗了 T_T
还是来看看正确的神建图吧。
考虑第i个工人,他修第j辆车只对后面要修的车有影响,而前面修过的车已经对当前没有影响了。 
而这个影响就是后面每个将要修理的车都多等待了time的时间。 
把每个工人拆成n个点,表示第几个工人第几次修车。 
每个车跟所有n×m个工人拆出的点连边。流量为1,费用为time[i,j]×k。(这里的k表示是倒数第几个修的) 
源点和每辆车连边,n×m个表示工人的点和汇点连边,流量都为1,费用同为0。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define N 100000
using namespace std;
int n,m,cnt,tot=-1,dis[N],can[N],last[N];
int next[N*2],point[N],v[N*2],remain[N*2],c[N*2],minn,flow;
int mincost=0;
bool vis[N];
const int inf=1e9;
void add(int x,int y,int z,int k)
{
  tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; c[tot]=k;
  tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; c[tot]=-k;
}
int addflow(int s,int t)
{
  int now=t; int ans=inf;
  while (now!=s)
  {
    ans=min(ans,remain[last[now]]);
    now=v[last[now]^1];
  }
  now=t;
  while (now!=s)
  {
  	remain[last[now]]-=ans;
  	remain[last[now]^1]+=ans;
  	now=v[last[now]^1];
  }
  return ans;
}
bool spfa(int s,int t)
{
  memset(dis,0x7f,sizeof(dis));
  memset(can,0,sizeof(can));
  dis[s]=0; can[s]=1;
  queue<int> p;	
  p.push(s);
  while(!p.empty())
  {
  	int now=p.front(); p.pop();
  	for (int i=point[now];i!=-1;i=next[i])
  	if (dis[v[i]]>dis[now]+c[i]&&remain[i])
  	{
  	  dis[v[i]]=dis[now]+c[i];
  	  last[v[i]]=i;
  	  if (can[v[i]]==0)
  	  {
  	  	can[v[i]]=1; 
  	  	p.push(v[i]);
  	  }
  	}
   can[now]=0;
  }
  if (dis[t]>inf)  return false;
  int k=addflow(s,t);
  mincost+=k*dis[t];
  return true;
}
void maxflow(int s,int t)
{
  while (spfa(s,t));
}
int main()
{
 memset(point,-1,sizeof(point));
 memset(next,-1,sizeof(next));
 scanf("%d%d",&m,&n);
 for(int i=1;i<=n;i++)
  add(0,i,1,0);
 for (int i=1;i<=n;i++)
 {
    for (int j=1;j<=m;j++)
    {
     int x; scanf("%d",&x);
     for (int k=1;k<=n;k++)
      add(i,(j-1)*n+k+n,1,x*k);
    }
 }
 cnt=n+n*m+1;
 for (int i=1;i<=m*n;i++)
   add(i+n,cnt,1,0);
 maxflow(0,cnt);
 //cout<<flow<<endl;
 printf("%0.2lf\n",(double)(mincost*1.0/n));
}




你可能感兴趣的:(bzoj 1070: [SCOI2007]修车)