1070: [SCOI2007]修车
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 1303 Solved: 443
[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)
解析:
先将n个顾客分别与原点连一条容量为1,费用为0的边。。。
再将m个技术人员每个分成n个点,分别与n个顾客连容量为1,费用为k*time[i][j]的边(k表示它在这个技术人员分离出来的n个点中是第k个)。。。
相当于这个技术人员在第k个修这辆车。。。
最后在把所有拆出来的点汇点连于原点一样的边。。。最后除以n
代码:
/**************************************************************
Problem: 1070
User: jianing
Language: C++
Result: Accepted
Time:1136 ms
Memory:7320 kb
****************************************************************/
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define inf 100000000
int n,m,t;
struct node
{
int u,v,c,w,next;
}edge[200000];
int head[200000],l=0;
int map[100][100];
queue<int>q;
int pre[200000],dist[200000];
bool vis[200000];
void add(int u,int v,int c,int w)
{
//printf("%d %d %d %d\n",u,v,c,w);
edge[l].u=u;
edge[l].v=v;
edge[l].c=c;
edge[l].w=w;
edge[l].next=head[u];
head[u]=l++;
edge[l].u=v;
edge[l].v=u;
edge[l].c=0;
edge[l].w=-w;
edge[l].next=head[v];
head[v]=l++;
}
void read()
{
//freopen("SCOI2007.in","r",stdin);
//freopen("SCOI2007.out","w",stdout);
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&map[i][j]);
}
bool SPFA()
{
while(!q.empty())q.pop();
memset(pre,0,sizeof(pre));
memset(vis,0,sizeof(vis));
memset(dist,0x3f,sizeof(dist));
dist[0]=0;vis[0]=true;
q.push(0);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(edge[i].c && dist[u]+edge[i].w<dist[v])
{
dist[v]=edge[i].w+dist[u];
pre[v]=i;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
if(pre[t])return 1; else return 0;
}
void mcmf()
{
int ans=0;
while(SPFA())
{
int u=t;
int minn=inf;
while(u!=0)
{
minn=min(minn,edge[pre[u]].c);
u=edge[pre[u]].u;
}
u=t;
while(u!=0)
{
edge[pre[u]].c-=minn;
edge[pre[u]^1].c+=minn;
u=edge[pre[u]].u;
}
ans+=minn*dist[t];
}
double ret=(double)ans/(double)n;
printf("%.2lf\n",ret);
}
void work()
{
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
add(0,i,1,0);
for(int i=1;i<=n;i++)
{
for(int j=n+1;j<=n*m+n;j++)
{
int tt=j%n;
int tm=j/n;
if(tt==0)tt=n,tm--;
add(i,j,1,tt*map[i][tm]);
}
}
t=n+n*m+1;
for(int i=n+1;i<=n+n*m;i++)add(i,t,1,0);
mcmf();
}
int main()
{
read();
work();
return 0;
}