洛谷p2053最大最小费用流

由题意可知一个人不可以同时修很多辆车 所以如果一个人修很多车最小的话 那一定有一个顺序就是 修第一辆车 第二辆车 第三辆车。。。。 修第一辆车的时候 第二辆 ~ 第n辆都在等第一辆修 所以 时间就是为 第一辆的时间 * n 第二辆的时候就是 第二辆的时间 * n - 1 以此类推

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<cmath>
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;

const int N = 70 * 100,M = N * N  * 2;

int n,m,S,T;

int head[N],to[M],last[M],c[M],w[M],cnt = 1;
void add(int a,int b,int c1,int d){
    to[++cnt] = b;
    c[cnt] = c1;
    w[cnt] = d;
    last[cnt] = head[a];
    head[a] = cnt;
    to[++cnt] = a;
    c[cnt] = 0;
    w[cnt] = -d;
    last[cnt] = head[b];
    head[b] = cnt;
}

int dist[N],flag[N],incf[N],ne[N];
bool spfa(){
    memset(dist,0x3f,sizeof dist);
    memset(incf,0,sizeof incf);
    queue<int>q;
    q.push(S);
    dist[S] = 0;incf[S] = 0x3f3f3f3f;
    while(q.size()){
        int p = q.front();
        q.pop();
        flag[p] = 0;
        for(int i = head[p]; i != -1; i = last[i]){
            int j = to[i];
            if(c[i] && dist[j] > dist[p] + w[i]){
                dist[j] = dist[p] + w[i];
                incf[j] = min(incf[p],c[i]);
                ne[j] = i;
                if(!flag[j]){
                    flag[j] = 1;
                    q.push(j);
                }
            }
        }
    }
    return incf[T] > 0;
}


int ek(){
    int sum = 0;
    while(spfa()){
        int k = incf[T];
        sum += k * dist[T];
        for(int i = T; i != S; i = to[ne[i] ^ 1]){
            c[ne[i]] -= k;
            c[ne[i] ^ 1] += k;
        }
    }
    return sum;
}

int main(){
    cin >> n >> m;
    memset(head,-1,sizeof head);
    S = 0,T = n * m + m + 1;
    for(int i = 1; i <= m; i++){
        add(S,i,1,0);
    }

    for(int i = 1; i <= m; i++){ //m辆车
        for(int j = 1; j <= n; j++){ //第j个人对 第i辆车的时间
            int x;
            cin >> x;
            for(int k = 1; k <= m; k++){ //倒数第k辆车修
                add(i,m + (j - 1) * m + k,1,x * k);
            }
        }
    }

    for(int i = 1; i <= n * m; i++){
        add(i + m,T,1,0);
    }

    printf("%.2lf\n",ek() * 1.0 / m);

    return 0;
}``

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值