ACM-ICPC Live Archive 5095 Transportation

最小费用最大流

2010的国赛题,题意很易懂不解释了。

分析部分参考了别人博客:一般的最小费用最大流是给出每个单位流量的费用,计算费用的时候是单位费用*流量,但是这里是单位费用*流量*流量,并不能单纯地计算,要巧妙地拆容量,每条边的原容量为cap,拆成cap条,每条容量都是1,第一次取这条路时是单位费用a,第二次是3*a,依次为5*a,7*a,9*a,这样你会发现,这条路走容量2的话刚好是4a,3为9a,4为16a,5为25a,接下来做一最小费用最大流即可

 

另外注意一点,题中说明边数最大为5000,而每条边的容量最大为5,所以在开数组的时候应该开到 2*5*50000,原来的一条边要拆成cap条边,所以边数变为cap倍,即*5,因为邻接表建图,有向边还要保存它的反边,每条边再*2,一共是*10

 

整道题就是拆边巧妙,其余部分都是最小费用最大流的模板

#include <cstdio>

#include <cstring>

#include <vector>

#include <queue>

#include <algorithm>

using namespace std;

#define INF 0x3f3f3f3f

#define MAXN 110

#define MAXM 5010 //有向图



int nume;

struct edge

{

    int u,v,cap,cost,flow,next;

}e[10*MAXM];

int first[MAXN];

int d[MAXN];  //spfa最短路

int p[MAXN]; //增广记录路径

int N,M,K,S,T;



void add(int u, int v ,int cost ,int cap)

{

    e[nume].u=u; e[nume].v=v; 

    e[nume].cost=cost; e[nume].cap=cap; e[nume].flow=0;

    e[nume].next=first[u]; first[u]=nume++;

}



void build()

{

    memset(first,-1,sizeof(first));

    nume=0;

    S=0; T=N+1;

    //限制最大流为K

    add(S,1,0,K); add(1,S,0,0);

    add(N,T,0,K); add(T,N,0,0);

    for(int i=0; i<M; i++)

    {

        int u,v,cost,cap;

        scanf("%d%d%d%d",&u,&v,&cost,&cap);

        for(int j=1; j<=cap; j++) //拆边的方法

        {//每条边的容量为1,单位费用为(2*j-1)*cost,其实就是1,3,5,7,9

            add(u,v,(2*j-1)*cost,1);

            add(v,u,-(2*j-1)*cost,0);

        }

    }

}



bool spfa()

{

    queue<int>q;

    bool inq[MAXN];

    memset(inq,false,sizeof(inq));

    memset(d,0x3f,sizeof(d));

    memset(p,-1,sizeof(p));

    d[S]=0; q.push(S); inq[S]=true;

    while(!q.empty())

    {

        int u,v,cost,cap,flow;

        u=q.front(); q.pop(); inq[u]=false;

        for(int k=first[u]; k!=-1; k=e[k].next)

        {

            v=e[k].v; cost=e[k].cost; cap=e[k].cap; flow=e[k].flow;

            if(cap>flow && d[u]+cost < d[v])

            {

                d[v]=d[u]+cost;

                p[v]=k;

                if(!inq[v])

                {

                    q.push(v);

                    inq[v]=true;

                }

            }

        }

    }

    if(d[T]!=INF) return true;

    return false;

}



void mincost_maxflow()

{

    int FLOW=0,COST=0;

    while(spfa())

    {

        int min=INF;

        for(int k=p[T]; k!=-1; k=p[e[k].u])

            if(e[k].cap-e[k].flow<min) min=e[k].cap-e[k].flow;

        //printf("min=%d\n",min);

        for(int k=p[T]; k!=-1; k=p[e[k].u]) //增广

        {

            e[k].flow += min;

            e[k^1].flow -= min;

        }

        COST += d[T]*min;

        FLOW += min;

    }

    if(FLOW<K)

        printf("-1\n");

    else

        printf("%d\n",COST);

}



int main()

{

    while(scanf("%d%d%d",&N,&M,&K)!=EOF)

    {

        build();

        mincost_maxflow();

    }

    return 0;

}

 

你可能感兴趣的:(hive)