HDU_3667_Transportation(最小费用流)

来源:互联网 发布:iphone手机画图软件 编辑:程序博客网 时间:2024/04/29 04:22

Transportation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2477    Accepted Submission(s): 1059


Problem Description
There are N cities, and M directed roads connecting them. Now you want to transport K units of goods from city 1 to city N. There are many robbers on the road, so you must be very careful. The more goods you carry, the more dangerous it is. To be more specific, for each road i, there is a coefficient ai. If you want to carry x units of goods along this road, you should pay ai * x2 dollars to hire guards to protect your goods. And what’s worse, for each road i, there is an upper bound Ci, which means that you cannot transport more than Ci units of goods along this road. Please note you can only carry integral unit of goods along each road.
You should find out the minimum cost to transport all the goods safely.
 

Input
There are several test cases. The first line of each case contains three integers, N, M and K. (1 <= N <= 100, 1 <= M <= 5000, 0 <= K <= 100). Then M lines followed, each contains four integers (ui, vi, ai, Ci), indicating there is a directed road from city ui to vi, whose coefficient is ai and upper bound is Ci. (1 <= ui, vi <= N, 0 < ai <= 100, Ci <= 5)
 

Output
Output one line for each test case, indicating the minimum cost. If it is impossible to transport all the K units of goods, output -1.

 

Sample Input
2 1 21 2 1 22 1 21 2 1 12 2 21 2 1 21 2 2 2
 

Sample Output
4-13
 
题意:求从城市1运送K单位物品到城市n的最小花费。给定的有向边,每条边都有其容量c,并且,产生的费用是 a * ( f * f ),其中f是这条边上的流量,a是给出的系数。

分析:这个题貌似是刘汝佳大白书当作一种典型的建图方法:拆边法。假如给定一条边(u,v),其计费系数为a,容量为c,那么可以把(u,v)拆成5条边,费用为(1a,3a,5a,7a,9a),容量都为1,为何这样子建图是有效的呢?很明显,假设流量为1,根据最短路优先原则那么肯定走的是cost=1a的那条边;若流量为2,肯定走的是cost=(1a,3a)的两条边;若流量为3,肯定走的是cost=(1a,3a,5a)三条边;若流量为4,那么则走cost=(1a,3a,5a,7a)四条边;若流量为5,那么走(1a,3a,5a,7a,9a)五条边。对所有输入的有向边,按照上述方法拆边建图,然后加入超级源点s(0),s连向1,容量为K,费用为0。然后跑一遍最小费用最大流,若流量不等于K,则输出-1,否则输出最小费用。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667

代码清单:
#include<map>#include<set>#include<cmath>#include<queue>#include<stack>#include<ctime>#include<cctype>#include<string>#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;#define end() return 0typedef long long ll;typedef unsigned int uint;typedef unsigned long long ull;const int maxn = 100 + 5;const int INF = 0x7f7f7f7f;struct Edge{    int from,to,cap,flow,cost;    Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){}};struct MCMF{    int n,m,flow,cost;    vector<Edge>edge; //边数的两倍    vector<int>G[maxn]; //邻接表,G[i][j]表示i的第j条边在e数组中的序号    int inq[maxn]; //是否在队列    int d[maxn]; //Bellman-Ford    int p[maxn]; //上一条弧    int a[maxn]; //可改进量    void init(int n){        this -> n = n;        for(int i=0;i<=n;i++) G[i].clear();        edge.clear();    }    void addEdge(int from,int to,int cap,int cost){        edge.push_back(Edge(from,to,cap,0,cost));        edge.push_back(Edge(to,from,0,0,-cost));        m=edge.size();        G[from].push_back(m-2);        G[to].push_back(m-1);    }    bool BellmanFord(int s,int t,int& flow,int& cost){        memset(d,INF,sizeof(d));        memset(inq,0,sizeof(inq));        d[s]=0; inq[s]=1; p[s]=0; a[s]=INF;        queue<int>q;        q.push(s);        while(!q.empty()){            int u=q.front();q.pop();            inq[u]=0;            for(int i=0;i<G[u].size();i++){                Edge& e=edge[G[u][i]];                if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){                    d[e.to]=d[u]+e.cost;                    p[e.to]=G[u][i];                    a[e.to]=min(a[u],e.cap-e.flow);                    if(!inq[e.to]){                        q.push(e.to);                        inq[e.to]=1;                    }                }            }        }        if(d[t]==INF) return false;        flow+=a[t];        cost+=d[t]*a[t];        for(int u=t;u!=s;u=edge[p[u]].from){            edge[p[u]].flow+=a[t];            edge[p[u]^1].flow-=a[t];        }        return true;    }    //需要保证初始网络中没有负权圈    void MincostMaxflow(int s,int t){        flow=0,cost=0;        while(BellmanFord(s,t,flow,cost));    }};struct EDGE{    int u,v,a,c;    EDGE(){}    EDGE(int u,int v,int a,int c):u(u),v(v),a(a),c(c){}};int N,M,K;int u,v,a,c;EDGE edges[5005];MCMF mcmf;void input(){    for(int i=1;i<=M;i++){        scanf("%d%d%d%d",&u,&v,&a,&c);        edges[i]=EDGE(u,v,a,c);    }}void createGraph(){    mcmf.init(N+1);    mcmf.addEdge(0,1,K,0);    for(int k=1;k<=M;k++){        int x=edges[k].c*edges[k].c;        for(int i=1,j=1;j<=x;i+=2,j+=i){            mcmf.addEdge(edges[k].u,edges[k].v,1,edges[k].a*i);        }    }}void solve(){    createGraph();    mcmf.MincostMaxflow(0,N);    if(mcmf.flow==K) printf("%d\n",mcmf.cost);    else printf("-1\n");}int main(){    while(scanf("%d%d%d",&N,&M,&K)!=EOF){        input();        solve();    }end();}


0 0
原创粉丝点击