[SCOI2007]修车 BZOJ 1070
Time Limit: 1 Sec Memory Limit:162 MB
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
3 2
1 4
Sample Output
1.50
HINT
数据范围:
(2<=M<=9,1<=N<=60), (1<=T<=1000)
拿到题目,看起来很好写,根据读入给每个技术人员和顾客之间连边(流量为1,费用为读入的时间),再加入源和汇
然后跑一次费用流,得出来的答案要除以顾客人数,然后样例很容易就过了,在本机一测,很不幸的WA完了。。。。。
回过头来看题,仔细分析了一下,发现,刚才的程序中,我们没有累加上仍在等待的顾客的时间【如两个技术人员,三个顾客,那么必定有一个顾客会多等一会儿,这一段时间我们没有算进来】
前思后想不知道怎么累加,因为网络流有退流的思想,而与此同时我们不能很好的维护出这个多余的时间,So how to do it ?
我们可以换一个思路,想想以前做的网络流,如方格取数等等,都是拆点的(虽然这一体的拆点和那一题没有一点思想上的关联。。。。)
我们把每个技术人员分别拆成N个点,第K个点表示当前技术人员在修好前K-1个后来修第K个,所以这条边的费用应该是K*w(w为读入的时间)【应该能明白吧~】
这样,本题就解决了
如果你在BZOJ上提交,你要注意了,1s是总时限,由于你每次spfa需要memset,所以,你要memset的数组千万不要太大,否则会超时的。。。。。(坑死我了。。。)
测评情况(BZOJ)
C++ AC Code
/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
#include<cstring>
#include<queue>
using std::queue;
const int N=100;
const int M=100*100*10;
const int inf=0x3f3f3f3f;
int worker,costomer,map[N][N];
struct EG{int from,to,flow,cost,next;}edge[M];
int head[M],L,S,T;
int dist[M],inQ[M],pre[M];
queue<int> Q;
void add_edge(int a,int b,int c,int d)
{
edge[L]=(EG){a,b,c,+d,head[a]};
head[a]=L++;
edge[L]=(EG){b,a,0,-d,head[b]};
head[b]=L++;
}
void read()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&worker,&costomer);
for(int i=1;i<=costomer;i++)
for(int j=1;j<=worker;j++)
scanf("%d",&map[j][i]);
int cnt=costomer;
for(int i=1;i<=worker;i++)
for(int k=1;k<=costomer;k++)
{
++cnt;
for(int j=1;j<=costomer;j++)
add_edge(cnt,j,1,k*map[i][j]);
}
S=0;T=cnt+1;
for(int i=costomer+1;i<=cnt;i++)
add_edge(S,i,1,0);
for(int i=1;i<=costomer;i++)
add_edge(i,T,1,0);
}
bool spfa()
{
memset(dist,0x3f,sizeof(dist));
memset(inQ,0,sizeof(inQ));
dist[S]=0; Q.push(S);
while(!Q.empty())
{
int x=Q.front();
Q.pop(); inQ[x]=0;
for(int i=head[x];i!=-1;i=edge[i].next)
if(edge[i].flow>0 && dist[edge[i].to]>dist[x]+edge[i].cost)
{
pre[edge[i].to]=i;
dist[edge[i].to]=dist[x]+edge[i].cost;
if(!inQ[edge[i].to])
{
inQ[edge[i].to]=1;
Q.push(edge[i].to);
}
}
}
return dist[T]!=inf;
}
void work()
{
int mincost=0;
while(spfa())
{
int res=inf;
for(int i=T;i!=S;i=edge[pre[i]].from)
res=std::min(res,edge[pre[i]].flow);
for(int i=T;i!=S;i=edge[pre[i]].from)
{
edge[pre[i]].flow-=res;
edge[pre[i]^1].flow+=res;
}
mincost+=dist[T]*res;
}
//printf("%d\n",mincost);
printf("%.2lf\n",(double)mincost/costomer);
}
int main()
{
freopen("repair.in","r",stdin);
freopen("repair.out","w",stdout);
read();
work();
return 0;
}