zoukankan      html  css  js  c++  java
  • hdu 3667(最小费用最大流+拆边)

    Transportation

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


    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 2 1 2 1 2 2 1 2 1 2 1 1 2 2 2 1 2 1 2 1 2 2 2
     
    Sample Output
    4 -1 3
     
    Source
     
    题意:现在有一个人要从1号点运送k个单位的货物到n号点,每一条边都有一个系数a,从第i条边运送x个单位的货物所需的费用是 ai*x*x,第i条边有个容量上限Ci,问运送这k个单位的货物所需的最小费用,如果不能运送,输出-1。
    题解:参考自刘汝佳的<算法竞赛-训练指南>,由于每个边的容量上限不会超过5,而我们每次运送的也是整数,所以可以利用拆边来表示一条容量为Ci的边能够运送的所有可能,假设Ci==5,那么拆成5条容量为1的边,费用分别为 1*ai,3*ai,5*ai,7*ai,9*ai,那么所有的 x*x 都可以由这几条边组合而成,然后设定超级源点和1号点的容量为 k,n号点和超级汇点的容量为k ,这样的话就限制了最大流不会超过k.然后跑一遍MCMF,判断一下maxflow是否为k,是的话,输出mincost,不是的话,输出 -1。
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    const int INF = 999999999;
    const int N = 200;
    const int M = 100005;
    struct Edge{
        int u,v,cap,cost,next;
    }edge[M];
    int head[N],tot,low[N],pre[N];
    int total ;
    bool vis[N];
    void addEdge(int u,int v,int cap,int cost,int &k){
        edge[k].u=u,edge[k].v=v,edge[k].cap = cap,edge[k].cost = cost,edge[k].next = head[u],head[u] = k++;
        edge[k].u=v,edge[k].v=u,edge[k].cap = 0,edge[k].cost = -cost,edge[k].next = head[v],head[v] = k++;
    }
    void init(){
        memset(head,-1,sizeof(head));
        tot = 0;
    }
    bool spfa(int s,int t,int n){
        memset(vis,false,sizeof(vis));
        for(int i=0;i<=n;i++){
            low[i] = INF;
            pre[i] = -1;
        }
        queue<int> q;
        low[s] = 0;
        q.push(s);
        while(!q.empty()){
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int k=head[u];k!=-1;k=edge[k].next){
                int v = edge[k].v;
                if(edge[k].cap>0&&low[v]>low[u]+edge[k].cost){
                    low[v] = low[u] + edge[k].cost;
                    pre[v] = k; ///v为终点对应的边
                    if(!vis[v]){
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        if(pre[t]==-1) return false;
        return true;
    }
    int MCMF(int s,int t,int n){
        int mincost = 0,minflow,flow=0;
         while(spfa(s,t,n))
        {
            minflow=INF+1;
            for(int i=pre[t];i!=-1;i=pre[edge[i].u])
                minflow=min(minflow,edge[i].cap);
            flow+=minflow;
            for(int i=pre[t];i!=-1;i=pre[edge[i].u])
            {
                edge[i].cap-=minflow;
                edge[i^1].cap+=minflow;
            }
            mincost+=low[t]*minflow;
        }
        total=flow;
        return mincost;
    }
    int n,m,k;
    bool flag[N][N];
    int main(){
        while(scanf("%d%d%d",&n,&m,&k)!=EOF){
            init();
            memset(flag,-1,sizeof(flag));
            int src = 0,des = n+1;
            for(int i=1;i<=m;i++){
                int u,v,a,c;
                scanf("%d%d%d%d",&u,&v,&a,&c);
                for(int j=0;j<c;j++){
                    addEdge(u,v,1,(2*j+1)*a,tot);
                }
            }
            addEdge(src,1,k,0,tot);
            addEdge(n,des,k,0,tot);
            int mincost = MCMF(src,des,n+2);
            if(total<k) printf("-1
    ");
            else printf("%d
    ",mincost);
        }
    }
  • 相关阅读:
    C#中的Singleton模式
    C#中的TemplateMethod模式
    从汉堡加料说起——浅谈C#中的Decorator模式
    轻松实现记录与撤销——C#中的Command模式
    分布式系统一致性问题与Raft算法(上)
    Scala函数式编程(五) 函数式的错误处理
    Spark RPC框架源码分析(三)Spark心跳机制分析
    AnalyticDB实现和特点浅析
    java并发编程 --并发问题的根源及主要解决方法
    数据的存储结构浅析LSM-Tree和B-tree
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5731044.html
Copyright © 2011-2022 走看看