Design and Analysis of Algorithms 6.5 vehicle maintenance .md

★ Title Description

N clients have to wait for the car service, and now the M maintenance staff, maintenance workers repair each different time for each car,

Please arrange each service member in need of repair and car maintenance order, so that all customers always wait a minimum of time.

★ input format

The first two digital input line M, N (1 <= N, M <= 20,1 <= K <= 20), indicates the number of vehicles and the number of maintenance staff.

Next N lines M digital Ti, j (1 <= Ti, j <= 20) represents the j-th vehicle maintenance worker needs repair i-Ti, j time

★ output format

The total output of the minimum waiting time.

★ sample input

2 2
3 2
1 4

★ Sample Output

3

★ Tips

no

★ reference code

/*
这道题是最小费用网络

现在问题是要如何构建这个网络图

如何表达一辆车对总等待时间的贡献?
第i号车是第j位维修员修理的倒数第k辆车,那么对总时间的贡献 T = k*T[i,j] 
(为了表达简洁,这里用“倒数第k辆车”,这样对结果没有影响)

网络图如上所示

现在就是依据这张图,求最大流量的最小费用 
*/
#include<bits/stdc++.h>
using namespace std;

int M,N;
int T[20+5][20+5]; 
struct Edge{
    int to,next,flow,dis;//flow流量 dis花费 
}E[10000]; //保存的数据是边 
int H[10000], numEdge;
void AddEdge(int u, int v, int f, int d){
    ++numEdge;
    E[numEdge].to=v;
    E[numEdge].flow=f;
    E[numEdge].dis=d;
    E[numEdge].next=H[u]; 
    H[u]=numEdge;
}


bool vis[10000];
int dis[10000],pre[10000],last[10000],flow[10000];//dis最小花费;pre每个点的前驱;last每个点的所连的前一条边;flow源点到此处的流量 
int maxflow,mincost;
queue <int> q; //保存的数据是点(从起点到终点) 


//使用深度优先DFS方法查找所有的增广路径 
int spfa(int s,int t){
    memset(dis,0x7f,sizeof(dis));
    memset(flow,0x7f,sizeof(flow));
    memset(vis,0,sizeof(vis));
    q.push(s); vis[s]=1; dis[s]=0; pre[t]=-1;

    while (!q.empty()) {
        int now=q.front(); q.pop();
        vis[now]=0; 
        for(int i=H[now]; i!=-1; i=E[i].next) {//从前端点now出发连着很多的后端点i 
            if(E[i].flow>0 && dis[E[i].to]>dis[now]+E[i].dis) { //第i条边还有余量,且会使费用更小 
                dis[E[i].to]=dis[now]+E[i].dis;
                pre[E[i].to]=now; //每个点所连的前端点是now 
                last[E[i].to]=i; //每个点的所连的前一条边 
                flow[E[i].to]=min(flow[now],E[i].flow);//最大流量取决于最小容量 
                if(!vis[E[i].to]) {
                    vis[E[i].to]=1;
                    q.push(E[i].to);
                }
            }
        }
    }
    return pre[t];
}


int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>M>>N;
    int sta=0, end=N+M*N+1; //“超级源点”和“超级结点”
    for(int i=1; i<=N; ++i) for(int j=1; j<=M; ++j){
        cin>>T[i][j];
    } 
    
    //构建网络图
    memset(H,-1,sizeof(H)), numEdge=-1; 
    for(int i=1; i<=N; ++i){
        AddEdge(sta, i, 1, 0); //从“超级源点”到“第i辆车” 
        AddEdge(i, sta, 0, 0);
        
        for(int j=1; j<=M; ++j) for(int k=1; k<=N; ++k){ 
            AddEdge(i, j*N+k, 1, k*T[i][j]); //从“第i辆车”到“第j个维修员修的倒数第k辆车”
            AddEdge(j*N+k, i, 0, -k*T[i][j]);
            if(i==N){
                AddEdge(j*N+k, end, 1, 0); //从“第j个维修员修的倒数第k辆车”到“超级结点” 
                AddEdge(end, j*N+k, 0, 0);
            }
        }
    }
    
    //求最大流最小费用 
    int maxflow=0, mincost=0;
    while(spfa(sta, end)!=-1) {  //迭代,不断的更新网络 
        maxflow+=flow[end];
        mincost+=flow[end]*dis[end];
        int now=end;
        while(now!=sta) {//从源点一直回溯到汇点 
            E[last[now]].flow-=flow[end];//flow和dis容易搞混 
            E[last[now]^1].flow+=flow[end];
            now=pre[now];
        }
    }
    cout<<mincost<<endl;
    return 0;
}

Guess you like

Origin www.cnblogs.com/yejifeng/p/12113492.html