您的位置:首页 > 其它

hdu 3667 Transportation(拆边费用流)

2013-11-04 21:18 274 查看
题目大意:要求从点1运输K件货物到点N,每对顶点间的费用为 a*x*x,其中x为该段路的流量,a为一个费用参数。求最小费用。

思路:题目明显是最小费用最大流问题,考虑到每段路的最大流量小于5,则可以将边拆开。比如s->e之间可以运输3件货物,那么将s->e拆成3条边(每条边视作不同的路),流量为1(只能走一次),假如单位费用为a,则该三条边的费用分别为a*1,a*3,a*5,假如该三条路都走了,就相当于直接从s到e运输三件货物,费用为a*3*3 = a*(1 + 3 + 5); 因为在该条路上运输2件货物这个问题上是包含了运输1件货物的,所以如果走了运输量为2件的这条路,潜意思就是运输量为1件的路也走了,所以当添加s->e且数量为2件的时候,费用应该为a*2*2-a*1*1
= 3*a,也就是 a*(n*n)-a*((n-1)*(n-1)) = 2*n - 1.

最后构造一个源点连接到起始点1上,费用为0,流量为K。



#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
#define INF 0xfffffff
#define MAX 105
struct node
{
    int v,c,cost,next;
}edge[MAX*1005];

int head[MAX];
int top;

int N,M,K;

int s,t,pt;
int pre[MAX],pp[MAX];
int dis[MAX];
bool vist[MAX];

void add(int u,int v,int c,int cost)
{
    edge[top].v = v;
    edge[top].c = c;
    edge[top].cost = cost;
    edge[top].next = head[u];
    head[u] = top ++;
    edge[top].v = u;
    edge[top].c = 0;
    edge[top].cost = - cost;
    edge[top].next = head[v];
    head[v] = top ++;
}

bool spfa()
{
    queue <int> Q;
    memset(vist,false,sizeof(vist));
    memset(pp,-1,sizeof(pp));
    memset(pre,-1,sizeof(pre));
    for(int i=0; i<=pt; i++)   dis[i] = INF;          
    dis[s] = 0;
    pre[s] = s;
    Q.push(s);
    vist[s] = true;
    while(!Q.empty())
    {
        int cur = Q.front();
        Q.pop();
        vist[cur] = false;
        for(int i=head[cur]; i!=-1; i=edge[i].next)
        {
            int v = edge[i].v;
            if(edge[i].c > 0 && dis[v] > dis[cur] + edge[i].cost)
            {
                dis[v] = dis[cur] + edge[i].cost;
                pre[v] = cur;
                pp[v] = i;
                if(!vist[v])
                {
                    Q.push(v);
                    vist[v] = true;
                }
            }
        }
    }
    if(dis[t] == INF)
        return false;
    return true;
}

int end()
{
    int flow = 0,mincost = 0,minflow;
    while(spfa())
    {
         minflow = INF;
        for(int i=t; i!=s; i=pre[i])
            minflow = min(minflow,edge[pp[i]].c);
        flow += minflow;
        mincost += minflow*dis[t];
        for(int i=t; i!=s; i=pre[i])
        {
            edge[pp[i]].c -= minflow;
            edge[pp[i]^1].c += minflow;
        }
    }
    if(flow < K)
        return -1;
    return mincost;
}

int main()
{
    while(~scanf("%d%d%d",&N,&M,&K))
    {
        top = 0;
        memset(head,-1,sizeof(head));
        for(int i=1; i<=M; i++)
        {
            int s,e,v,c;
            scanf("%d%d%d%d",&s,&e,&v,&c);
            for(int j=1; j<=c; j++)
                add(s,e,1,v*(2*j-1));
        }
        s = 0;
        t = N+1;
        pt = N + 2;
        add(s,1,K,0);
        add(N,t,K,0);
        int ans = end();
        printf("%d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: