Jam's store
Accepts: 15
Submissions: 42
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
Jam不好好学习,然后就去帮别人修电脑了,在一家店里,有M个店员,现在有N个顾客,给出每个顾客对应给每个店员的修电脑的时间为Tij,问所有顾客要等待的最少时间。当然,一个顾客在某个店员那里完成之后,那个店员才会执行下一个顾客的任务
输入描述
第一行T(1≤T≤100),表示T组数据。 接下来T组数据: 每组数据第一行为M,N(1≤M,N≤20)表示店员数和顾客数 接下来N行M列,每个整数表示第i个顾客找第j个店员的时间(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
分析:经典的建图。这道题问的是所有顾客花费的最小总时间,并且一个店员只能给一个顾客服务。也就是说,当所有店员在工作时,顾客只能等待。那么,考虑顾客A是店员M的最后一个顾客,顾客B是店员M倒数第二个顾客,那么A不耽搁其他人的时间,B会耽搁A的时间。即A会用TA+TB(TB是他等的时间),总的时间要用2*TB+TA。
即B这个人就影响了后面的人,又如C是M店员倒数三的顾客那么,他会影响后面的人时间为3*TC。所以,建图方式:枚举N个顾客是M店员的倒数第几个顾客,因此将每个店员拆成N个点。第i个顾客是店员j的倒数第k个顾客:add(i,j',k*c),j'是拆点后的编号,c为花费的时间。最后将所有j'连接到一个虚的汇点t,add(j',t',1,0)。最后这个虚汇点连到总汇点,add(t',t,n,0).
#include<iostream> #include<string> #include<stdio.h> #include<string.h> #include<vector> #include<math.h> #include<queue> #include<map> #include<set> #include<algorithm> using namespace std; #define MAXN 10005 #define LL long long #define INF 0x3f7f7f7f const double eps = 1e-10; struct Edge { int from,to,cap,flow,cost; Edge(int from=0,int to=0,int cap=0,int flow=0,int cost=0) { this->from=from; this->to=to; this->cap=cap; this->flow=flow; this->cost=cost; } }; vector<Edge>edges; vector<int>g[MAXN]; bool vis[MAXN]; int dis[MAXN]; int pre[MAXN]; int a[MAXN]; int s,t,n,m; void init() { for(int i=0;i<MAXN;i++) { g[i].clear(); } edges.clear(); } void add(int from,int to,int cap,int cost) { edges.push_back(Edge(from,to,cap,0,cost)); edges.push_back(Edge(to,from,0,0,-cost)); int m=edges.size(); g[from].push_back(m-2); g[to].push_back(m-1); } bool spfa(int &flow,int &cost) { int i; for(i=0;i<MAXN;i++) dis[i]=INF; memset(vis,0,sizeof(vis)); queue<int>q; q.push(s); dis[s]=0; vis[s]=1; pre[s]=0; a[s]=INF; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; int sz=g[u].size(); for(i=0;i<sz;i++) { Edge &e=edges[g[u][i]]; if(e.cap>e.flow&&dis[e.to]>dis[u]+e.cost) { dis[e.to]=dis[u]+e.cost; pre[e.to]=g[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!vis[e.to]) { vis[e.to]=1; q.push(e.to); } } } } if(dis[t]==INF) return false; flow+=a[t]; cost+=dis[t]*a[t]; int v=t; while(v!=s) { edges[pre[v]].flow+=a[t]; edges[pre[v]^1].flow-=a[t]; v=edges[pre[v]].from; } return true; } int minCost() { int flow=0,cost=0; while(spfa(flow,cost)); return cost; } int maze[125][125]; int main() { int i,j; int cas; scanf("%d",&cas); while(cas--) { scanf("%d%d",&m,&n); init(); for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { scanf("%d",&maze[i][j]); } } s=0;t=1000; for(i=1;i<=n;i++) add(s,i,1,0); int cnt=n+1; for(j=1;j<=m;j++)//枚举每个店员 { for(int k=1;k<=n;k++)//倒数第k个服务对象 { ++cnt; for(i=1;i<=n;i++)//枚举是那个对象(顾客) { add(i,cnt,1,maze[i][j]*k); } add(cnt,t,1,0); } } add(t,t+1,n,0); t++; cout<<minCost()<<endl; } return 0; }