uva10746 (最小费用最大流)

题目大意:
有n所银行,有m辆巡警车,给出巡警车到各个银行所需要的距离,问平均最小的距离是多少。
思路:
最小费用最大流的问题。
构造一个超级源点,然后连接边到各辆巡警车,巡警车与各所银行相连接,容量为1,费用为k。先求出费用最小的路,然后在费用最小的路上增流

代码:

#include <iostream>
using namespace std;
#include <cstring>
#include <stdio.h>
#include <queue>
int n,m;
#define eps 1e-6
const int MAX = 102;
const int INF = 0x3f3f3f3f;
struct node {
    int u,v;
    double cost;
    int cap;
    int flow;
    int ne;
}e[10000];

int first[MAX],p[MAX];
double dis[MAX];
int vis[MAX];
int edgenum;
int F;
int s,t;
double c;
void add(int u,int v,int cap,double w) {
    e[edgenum].u = u;
    e[edgenum].v = v;
    e[edgenum].flow = 0;
    e[edgenum].cap = cap;
    e[edgenum].cost = w;
    e[edgenum].ne = first[u];
    first[u] = edgenum++;
    e[edgenum].u = v;
    e[edgenum].v = u;
    e[edgenum].flow = 0;
    e[edgenum].cap = 0;
    e[edgenum].cost = -w;
    e[edgenum].ne = first[v];
    first[v] = edgenum++;
}
void EK() {
    queue<int> q;
    F = 0;
    c = 0;
    while(1) {
        for(int i = 0; i <= t; i++)
            dis[i] = INF;
        dis[0] = 0;
        memset(vis,0,sizeof(vis));
        memset(p,-1,sizeof(p));
        q.push(s);
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for(int k = first[u]; k != -1; k = e[k].ne) {
                int v = e[k].v;
                if(e[k].cap > e[k].flow && dis[v] > dis[u] + e[k].cost + eps) {
                    dis[v] = dis[u] + e[k].cost;
                    p[v] = k;
                    if(!vis[v]) {
                        vis[v] = 1;
                        q.push(v);
                    }

                }
            }
        }
        if(dis[t] == INF)
            break;
        int a = INF;
        for(int u = p[t];u != -1; u = p[e[u^1].v])
            a = min(a,e[u].cap - e[u].flow);
        for(int  u = p[t];u != -1; u = p[e[u^1].v]) {
            e[u].flow += a;
            e[u ^1].flow -=a;
        }
        c += dis[t] *(double)a;//因为a肯定为1,所以无所谓有没有乘
        F += a;
    }
}
int main() {

    double k;
    while(scanf("%d%d",&n,&m) && n && m) {
        edgenum = 0;
        s = 0; 
        t = n + m + 1;
        memset(first,-1,sizeof(first));
        for(int i = 1; i <= m ; i++) {
            add(0,i,1,0);
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                int u = j;
                int v = m + i;
                scanf("%lf",&k);
                add(u,v,1,k);
            }
        }
        for(int i = m + 1; i <= n + m; i++) {
            add(i,t,1,0);
        }
        EK();
        printf("%.2f\n",c/n + eps);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值