您的位置:首页 > 其它

bzoj 1070: [SCOI2007]修车

2016-04-05 21:32 211 查看

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
,can
,last
;
int next[N*2],point
,v[N*2],remain[N*2],c[N*2],minn,flow;
int mincost=0;
bool vis
;
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));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: