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;
}

 

posted @ 2013-03-15 18:53  Titanium  阅读(544)  评论(0编辑  收藏  举报