HDU 3667Transportation(最小费用最大流)拆边,经典

Transportation

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2348 Accepted Submission(s): 1000

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

2010 Asia Regional Harbin

题意:

用 0 到 n-1 运送k 个货物,m条边,每条边,u,v,a,c,; 每条边表示 运送 x 单元货物的花费为 a * x*x,c 表示最大流量 ,

求 最小费用 ,若不能全部运送输出 -1;

题解: 拆边 ,看到这个题直接的思路就是费用流,一开始提了个模版 上去 发现不对,我们以前做的 花费是 a*f ,而现在是 a*f*f(此时 以 最短路 已不能找到正确的答案);

所以我们要变为 a*f ,那么就是,我们 发现 第一次运送时

费用为a,第二次取这条路时费用为3a(即流量为2时费用值为a+3a=4a),……,第i次取这条路时费用为(2*i-1)*a

在 u 到 u 连 c 条边,每条边的流量 为 1 ,费用 (2*i - 1)*a

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int MAXN = 100010;
const int MAXM = 100100;
const int INF = 1<<30;
struct EDG{
    int to,next,cap,flow;
    int cost;  //单价
}edg[MAXM];
int head[MAXN],eid;
int pre[MAXN], cost[MAXN] ; //点0~(n-1)

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
inline void addEdg(int u,int v,int cap,int cst){
    edg[eid].to=v; edg[eid].next=head[u]; edg[eid].cost = cst;
    edg[eid].cap=cap; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v]; edg[eid].cost = -cst;
    edg[eid].cap=0; edg[eid].flow=0; head[v]=eid++;
}

bool inq[MAXN];
int q[MAXN];
inline bool spfa(int sNode,int eNode,int n){
    int l=0 , r=0;

    for(int i=0; i<n; i++){
        inq[i]=false; cost[i]= INF;
    }
    cost[sNode]=0; inq[sNode]=1; pre[sNode]=-1;
    q[r++]=sNode;
    while(l!=r){
        int u=q[l++];
        if(l==MAXN)l=0;
        inq[u]=0;
        for(int i=head[u]; i!=-1; i=edg[i].next){
            int v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && cost[v]>cost[u]+edg[i].cost){ //在满足可增流的情况下,最小花费
                cost[v] = cost[u]+edg[i].cost;
                pre[v]=i;   //记录路径上的边
                if(!inq[v]){
                    if(r==MAXN)r=0;
                    q[r++]=v;
                    inq[v]=1;
                }
            }
        }
    }
    return cost[eNode]!=INF;    //判断有没有增广路
}
//反回的是最大流,最小花费为minCost
int minCost_maxFlow(int sNode,int eNode ,int& minCost,int n){
    int ans=0;
    while(spfa(sNode,eNode,n)){

        ans++;
        minCost+=cost[eNode];
        int i=pre[eNode];
        while(i!=-1){
            edg[i].flow+=1; edg[i^1].flow-=1;
            i=pre[edg[i^1].to];
        }
    }
    return ans;
}
inline void scanf(int& num){
    char ch;
    while(ch=getchar()){
        if(ch>=‘0‘&&ch<=‘9‘)break;
    }
    num=ch-‘0‘;
    while(ch=getchar()){
        if(ch<‘0‘||ch>‘9‘)break;
        num=num*10+ch-‘0‘;
    }
}
int main(){
    int n,m,k;
    while(scanf("%d%d%d",&n,&m,&k)>0){
        init();
        int s=0,t=n;
        addEdg(s , 1 , k , 0);
        while(m--){
            int u,v,a,c;
            scanf(u);
            scanf(v);
            scanf(a);
            scanf(c);
            for(int i=1; i<=c; i++)
            addEdg(u,v,1,a*(2*i-1));
        }
        int mincost=0;
        k-=minCost_maxFlow(s,t,mincost,t+1);
        if(k!=0)
         mincost=-1;
        printf("%d\n",mincost);
    }
}
时间: 2024-08-09 06:17:26

HDU 3667Transportation(最小费用最大流)拆边,经典的相关文章

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

hdu 2516 最小费用最大流

原来这个代码超时 #include<stdio.h> #include<queue> #include<string.h> using namespace std; #define N 200 #define inf 0x3fffffff int cap[N][N]; int fee[N][N]; int s,t,sum,pre[N]; int spfa() { queue<int>q; int dis[N],visit[N],u,i; memset(pre

hdu 1533(最小费用最大流)

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4223    Accepted Submission(s): 2178 Problem Description On a grid map there are n little men and n houses. In each unit time, every l

多校第一场:HDU 4862 最小费用最大流

思路:这题主要是建图搞了好久,以前没判断过满流,所以又看了这个知识点,然后才发现自己的最小费用最大流在求满流的时候有bug,正好改了过来. 建图:开始看题解知道这题是最小费用最大流,然后没看解释就做了.然后自己建的图没得求出答案,然后想了好久也没发现哪里错.然后看了官方题解,发现自己的建图和官方差太大了.可能是受昨天做POJ最小费用建图的影响吧.官方的建太符合题目意思了,只能说,我还看了好久建图才理解的. 构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0:Y部有N*M个

HDU 1533 最小费用最大流(模板)

http://acm.hdu.edu.cn/showproblem.php?pid=1533 这道题直接用了模板 题意:要构建一个二分图,家对应人,连线的权值就是最短距离,求最小费用 要注意void init(int n) 这个函数一定要写 一开始忘记写这个WA了好几发 还有这个题很容易T掉,赋值建图要简化,一开始构建成网络流那种图一直T #include <stdio.h> #include <string.h> #include <iostream> #includ

hdu 6437 /// 最小费用最大流 负花费 SPFA模板

题目大意: 给定n,m,K,W 表示n个小时 m场电影(分为类型A.B) K个人 若某个人连续看了两场相同类型的电影则失去W 电影时间不能重叠 接下来给定m场电影的 s t w op 表示电影的 开始时间s 结束时间t 看完这场电影则获得w 电影类型是op(0为A 1为B) 将一场电影拆成两个点 s t,两点间连线花费为-w容量为1 源点与所有电影的s点连线 花费为0容量为1 所有电影的t点与汇点连线 花费为0容量为1 若两场电影的时间不冲突 那么按时间顺序在之间连边 若类型相同 花费为W容量为

【网络流#2】hdu 1533 最小费用最大流模板题

嗯~第一次写费用流题... 这道就是费用流的模板题,找不到更裸的题了 建图:每个m(Man)作为源点,每个H(House)作为汇点,各个源点与汇点分别连一条边,这条边的流量是1(因为每个源点只能走一条边到汇点),费用是 从源点走到汇点的步数,因为有多个源点与汇点,要建一个超级源点与超级汇点,超级源点与各个源点连一条流量为1,费用为0(要避免产生多余的费用)的边 按照这个图跑一发费用流即可 把代码挂上去,用的是前向星写的 1 #include<cstdio> 2 #include<cstr

hdu3667 Transportation 拆边法+最小费用最大流

/** 题目:hdu3667 Transportation 拆边法+最小费用最大流 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667 题意:n个城市由m条有向边连接.要从城市1运输k流量到城市n.每条边有可以运输的流量容量,以及费用系数ai. 费用系数指该条边的费用为该条边的运输流量x的平方乘以ai.即ai*x^2. 如果无法运输k流量,输出-1,否则输出从城市1运输k流量到城市n的最小花费. 思路:拆边法+最小费用最大流 假设从u->v 容量为

hdu 4494 Teamwork 最小费用最大流

Teamwork Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4494 Description Some locations in city A has been destroyed in the fierce battle. So the government decides to send some workers to repair these location

HDU 4862 JUMP 最小费用最大流

2014 多校的B题,由于我不怎么搞图论,当时碰到这个题目,我怎么想都没往网络流方面弄,不过网络流真的是个好东西,对于状态多变,无法用动规或者数据结构来很好表示的时候,非常有用 这个题目要求每个点一定要访问到,并且每次访问的是没访问过的点,跳跃的方向为向右或者向下. 建图的时候,分成二分图,从一个超级源点向x部分建cap为1 cost为0的点,对所以可到达的点从x到y建cap为1,cost根据题目算出来,不过要算负值,因为我们要求得实际是最大费用,最后对结果求相反数即可.所有y部分的点对超级汇点