首页 > 代码库 > uva 10746 Crime Wave - The Sequel(最小费用流)

uva 10746 Crime Wave - The Sequel(最小费用流)

题目:

        链接:点击打开链接

题意:

一天n个银行被抢了,m个值班的警车在不同的位置,n个这样的警车应该被派往每个银行,以便平均到达n个银行的时间最少。

思路:

尽管题目很裸,还是不会做,看来还是差很多啊,。

单源,源点s=0,汇点t=n+m+1.警车编号1到m。银行编号m+1到n+m+1。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define INF 100000000

const int N = 50;
const double eps = 1e-8;

//cap表示边(u,v)的容量。flow表示实际运送的流量。cost为时间花费
int n,m;
int cap[N][N],flow[N][N];
double cost[N][N];
int s,t;

void init()
{
    double c;
    s = 0;
    t = n + m + 1;
    memset(cap,0,sizeof(cap));
    memset(flow,0,sizeof(flow));
    for(int i=0; i<=t; i++)
    {
        for(int j=0; j<=t; j++)
            cost[i][j] = INF;
    }
    for(int i=1; i<=m; i++)//源点和警车相连
    {
        cap[s][i] = 1;
        cost[s][i] = 0;
    }
    for(int i=m+1; i<t; i++)//银行和汇点相连
    {
        cap[i][t] = 1;
        cost[i][t] = 0;
    }
    for(int i=m+1; i<t; i++)
    {
        for(int j=1; j<=m; j++)
        {
            scanf("%lf",&c);
            cap[j][i] = 1;
            cost[i][j] = -c;
            cost[j][i] = c;
        }
    }
}

void EK()
{
    queue<int> q;
    int p[N];
    int a;
    int vis[N];
    double d[N],c = 0;
    for(;;)
    {
        memset(vis,0,sizeof(vis));
        for(int i=0; i<=t; i++)
            d[i] = INF;
        d[s] = 0;
        q.push(s);
        while(!q.empty())//BFS找增广路
        {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for(int v=s; v<=t; v++)
            {
                if(cap[u][v] > flow[u][v] && d[v] > d[u] + cost[u][v] + eps)//找到新结点v
                {
                    d[v] = d[u] + cost[u][v];
                    p[v] = u;//记录v的父亲,
                    if(!vis[v])
                    {
                        q.push(v);//并加入FIFO队列
                        vis[v] = 1;
                    }
                }
            }
        }
        if(d[t] == INF)
            break;
        a = INF;
        for(int u=t; u != s; u=p[u])//从汇点往回走
        {
            a = min(a,cap[p[u]][u] - flow[p[u]][u]);//a为s-v路径上的最小残量
        }
        for ( int u = t; u != s; u = p[u] )
        {
            flow[p[u]][u] += a;//更新正向流量
            flow[u][p[u]] -= a;//更新反向流量
        }
        c += d[t] * a;//从S流出的总流量
    }
    c /= n;//平均
    printf("%.2lf\n",c + eps);
}

int main()
{
    //freopen("input.txt","r",stdin);
    while(scanf("%d%d",&n,&m) != EOF && (n+m))
    {
        init();
        EK();
    }
    return 0;
}

-----------------------------------------------------------------------

收获:

最小费用最大流的建图:

cap边的容量,flow为实际的流量,还有花费cost。。。。。。。

应运EK增广路算法是要结合题目:

。。。。。。。。。。。。。。。。。。。。。。。

---------------------------------------------------------------------------

战斗,永不退缩;奋斗,永不停歇、、、、、、、、、、


uva 10746 Crime Wave - The Sequel(最小费用流)