问题描述
Jam不好好学习,然后就去帮别人修电脑了,在一家店里,有M个店员,现在有N个顾客,给出每个顾客对应给每个店员的修电脑的时间为Tij,问所有顾客要等待的最少时间。当然,一个顾客在某个店员那里完成之后,那个店员才会执行下一个顾客的任务
输入描述
第一行T(1≤T≤100),表示T组数据。
接下来T组数据:
每组数据第一行为M,N(1≤M,N≤20)表示店员数和顾客数
接下来NNN行MMM列,每个整数表示第iii个顾客找第jjj个店员的时间(1≤Tij≤1000)
输出描述
输出一个数,表示用时总时间
输入样例
1
4 3
4 4 1 5
8 2 5 6
4 5 10 5
输出样例
7
Hint
第1个顾客选择第3个员工
第2个顾客选择第2个员工
第3个顾客选择第1个员工
一共花费4+2+1=7
题意:不多叙述了,BC中文题
分析:此题很容易看出是费用流,只是建图的时候需要一定的技巧,我们要处理一个店员在给一个人修完电脑后给另一个人修的等待时间问题,因为一个店员最多可能被n个顾客找修电脑,所以我们把每个店员拆为n个点,正如BC官方题解所说,每一个点代表这是倒数第几个顾客去找他修电脑,假如一个顾客找他修电脑的时间为Tij,而且这个顾客是倒数第二个找他修电脑的,那么这个顾客产生的时间耽搁包括自己修电脑需要等待的时间加上倒数第一个人的等待时间,因为倒数第一个人需要等倒数第二个人修完才能去修,所以这个顾客需要连一条费用为Tij*2容量为1的边,连向这个店员的第二个拆点(第二个拆点是代表是倒数第二个人来找他修电脑)。对于一个店员,所有顾客找他的可能次序都连边,就像上面举例一样。具体细节还需要自己体会,文字表达能力太差,就只能说到这儿了。
下面附上自己的渣代码,拆点我没仔细想,反正只要拆点没有重合就行......
#include<cstdio>
#include<string.h>
#include<queue>
#include<algorithm>
#define maxn 3000
#define INF 0x3f3f3f
using namespace std;
struct node
{
int st;
int en;
int flow,cost;
int next;
}E[maxn*maxn];
int num;
int p[maxn];
void init()
{
memset(p,-1,sizeof p);
num=0;
}
void add(int st,int en,int flow,int cost)
{
E[num].st=st;
E[num].en=en;
E[num].flow=flow;
E[num].cost=cost;
E[num].next=p[st];
p[st]=num++;
E[num].st=en;
E[num].en=st;
E[num].flow=0;
E[num].cost=-cost;
E[num].next=p[en];
p[en]=num++;
}
int pre[maxn];
int dis[maxn];
bool fg[maxn];
bool spfa(int st,int en)
{
for(int i=0;i<=maxn;i++)
fg[i]=0,dis[i]=INF,pre[i]=-1;
queue<int>q;
q.push(st);
fg[st]=1;
dis[st]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
fg[u]=0;
for(int i=p[u];i+1;i=E[i].next)
{
int v=E[i].en;
if(E[i].flow&&dis[v]>dis[u]+E[i].cost)
{
dis[v]=dis[u]+E[i].cost;
pre[v]=i;
if(!fg[v])
{
fg[v]=1;
q.push(v);
}
}
}
}
if(dis[en]<INF)
return 1;
return 0;
}
int solve(int st,int en)
{
int ans=0,flow=0;
while(spfa(st,en))
{
int d=INF;
for(int i=pre[en];i+1;i=pre[E[i].st])
d=min(d,E[i].flow);
flow+=d;
for(int i=pre[en];i+1;i=pre[E[i].st])
{
E[i].flow-=d;
E[i^1].flow+=d;
ans+=d*E[i].cost;
}
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m,c;
int N=1000;
scanf("%d%d",&m,&n);
init();
int s=0,t=(m+1)*n+N+1;
for(int i=1;i<=m;i++)
{
for(int j=(i-1)*n+1;j<=i*n;j++)
{
add(j,j+N,1,0);
add(j+N,t,1,0);
}
}
for(int i=1;i<=n;i++)
{
add(s,m*n+i,1,0);
for(int j=1;j<=m;j++)
{
scanf("%d",&c);
for(int k=(j-1)*n+1,x=1;k<=j*n;k++,x++)
{
add(m*n+i,k,1,x*c);
}
}
}
printf("%d\n",solve(s,t));
}
return 0;
}