hdu 3667 拆边加最小费用流

Transportation

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

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

这题的重点是拆边,虽然之前没见过拆边的题目,但是这提这么简单的思路我竟然没想到,还是该给自己一个大耳光

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<cstring>
  5 #include<climits>
  6 #define MAXP 110
  7 #define MAXE 51000
  8 using namespace std;
  9 struct Edge
 10 {
 11     int s,t,f,c,next;
 12 } edge[MAXE];
 13 int head[MAXP];
 14 int pre[MAXP];
 15 int dist[MAXP];
 16 bool isq[MAXP];
 17 int n,m,k,s,t,u,v,c,f,ent;
 18 void add(int S,int T,int f,int c)
 19 {
 20     edge[ent].s=S;
 21     edge[ent].t=T;
 22     edge[ent].f=f;
 23     edge[ent].c=c;
 24     edge[ent].next=head[S];
 25     head[S]=ent++;
 26     edge[ent].s=T;
 27     edge[ent].t=S;
 28     edge[ent].f=0;
 29     edge[ent].c=-c;
 30     edge[ent].next=head[T];
 31     head[T]=ent++;
 32 }
 33 int MIN(int a,int b)
 34 {
 35     return a<b?a:b;
 36 }
 37 bool spfa()
 38 {
 39     memset(pre,-1,sizeof(pre));//初始化路径为-1
 40     for(int i=s; i<=t; i++)
 41     {
 42         isq[i]=false;//每点开始时均不在队列里面
 43         dist[i]=INT_MAX;//初始化到每点的最小费用均为INT_MAX
 44     }
 45     queue<int>q;
 46     q.push(s);
 47     isq[s]=true;//源点s已经放入到队列里面去了
 48     dist[s]=0;//从源点到源点的距离为0
 49     while(!q.empty())//当队列为空时优化过程结束,退出循环
 50     {
 51         int temp1=q.front();
 52         q.pop();
 53         isq[temp1]=false;//该点已经退出队列
 54         for(int i=head[temp1]; i!=-1; i=edge[i].next) //从该点找通过邻接表找所有的以该点为起点的边,从中找出能优化的点
 55         {
 56             int temp2=edge[i].t;
 57             if(edge[i].f&&dist[temp2]>dist[temp1]+edge[i].c)
 58             {
 59                 dist[temp2]=dist[temp1]+edge[i].c;
 60                 pre[temp2]=i;
 61                 if(!isq[temp2])//如果该点不在队列中,则将该点放入队列中
 62                 {
 63                     q.push(temp2);
 64                     isq[temp2]=true;
 65                 }
 66             }
 67         }
 68     }
 69     return pre[t]!=-1;//如果pre[t]==-1的话说明没有找到从s到t的路径,即已经找到所有的路径了,结束循环
 70 }
 71 void mcmf()
 72 {
 73     int tot=0;
 74     int sum=0;
 75     int mincost=INT_MAX;
 76     int minn=INT_MAX;
 77     while(spfa())
 78     {
 79         tot++;
 80         mincost=dist[t];
 81         sum+=mincost;
 82         if(tot==k)
 83         {
 84             printf("%d\n",sum);
 85             return;
 86         }
 87         for(int i=pre[t];i!=-1;i=pre[i])//最小费用最大流中的减流的过程
 88         {
 89             edge[i].f--;
 90             edge[i^1].f++;
 91             i=edge[i].s;
 92         }
 93     }
 94     printf("-1\n");
 95 }
 96 int main()
 97 {
 98     while(~scanf("%d%d%d",&n,&m,&k))
 99     {
100         ent=0;
101         memset(head,-1,sizeof(head));
102         s=1;t=n;
103         for(int i=1;i<=m;i++)
104         {
105             scanf("%d%d%d%d",&u,&v,&c,&f);
106             for(int j=1;j<=f;j++)
107                 add(u,v,1,(j*2-1)*c);
108         }
109         if(m==0||n==1)
110         {
111             printf("0\n");
112             continue;
113         }
114         mcmf();
115     }
116     return 0;
117 }

时间: 2024-10-13 06:52:10

hdu 3667 拆边加最小费用流的相关文章

Hdu 3667 Transportation(最小费用流+思路)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3667 思路:平方关系,直接建图每次增广并不是最优.... 1^2=1,2^2=1+3,3^2=1+3+5,4^2=1+3+5+7....... 所以,对于每条边<x,y>,若流量为c,则在x与y之间连c条边,流量均为1,费用分别为a[i],3*a[i],5*a[i].........由于每次增广时流量相同时选择最小花费的边,若该边<x,y>流量为c,则总花费为a[x]+3*a[x]+5

HDU 3667 Transportation(网络流之费用流)

题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k,需要让每一次增广到的流量都是1,这就需要把每一条边的流量都是1才行.但是每条边的流量并不是1,该怎么办呢.这个时候可以拆边,反正c最多只有5,拆成5条流量为1的边.但是这时候费用怎么办呢,毕竟平方的关系不能简单把每一条边加起来.这时候可以把拆的边的流量设为1,3,5,7,9.如果经过了3个流量,那就肯定会流1,3,5,费用为9,是3的平方,同理,其他的也是如此.然后按照给出的边建图跑一次费用流就可以了. 代码如下: #i

HDU 3488Tour(网络流之最小费用流)

题目地址:hdu3488 这题跟上题基本差不多啊....详情请戳这里. 另外我觉得有要改变下代码风格了..终于知道了为什么大牛们的代码的变量名都命名的那么长..我决定还是把源点与汇点改成source和sink吧..用s和t太容易冲突了...于是如此简单的一道题调试到了现在..sad... 代码如下: #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #

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 3667 费用流(拆边)

题意:有n个城市(1~n),m条有向边:有k件货物要从1运到n,每条边最多能运c件货物,每条边有一个危险系数ai,经过这条路的费用需要ai*x2(x为货物的数量),问所有货物安全到达的费用. 思路:c<=5,这里可以做文章:把每条边拆成c条边,容量都为1,费用为ai*(2*i-1)(第二个i是指拆边时的第几条边).推导:x2-(x-1)2=2x-1. 代码: 1 #include<stdio.h> 2 #include<string.h> 3 #define min(x,y)

HDU 3667 费用流 拆边 Transportation

题意: 有N个城市,M条有向道路,要从1号城市运送K个货物到N号城市. 每条有向道路<u, v>运送费用和运送量的平方成正比,系数为ai 而且每条路最多运送Ci个货物,求最小费用. 分析: 拆边,每条边拆成费用为a, 3a, 5a的边,这样就能保证每条边的费用和流量的平方成正比. 因为最多运送K个货物,所以增加一个源点和城市1连一条容量为K费用为0的边. 跑一边最小费用最大流,如果满流才有解. 1 #include <iostream> 2 #include <cstdio&

hdu 4004 (二分加贪心) 青蛙过河

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4004 题目意思是青蛙要过河,现在给你河的宽度,河中石头的个数(青蛙要从石头上跳过河,这些石头都是在垂直于河岸的一条直线上) 还有青蛙能够跳跃的 最多 的次数,还有每个石头离河岸的距离,问的是青蛙一步最少要跳多少米可以过河> 这是一道二分加贪心的题,从0到的河宽度开始二分,二分出一个数然后判断在这样的最小步数(一步跳多少距离)下能否过河 判断的时候要贪心 主要难在思维上,关键是要想到二分上去,能想到

HDU 3667

http://acm.hdu.edu.cn/showproblem.php?pid=3667 最小费用最大流 本题流量和费用不是线性关系,fee=a*flow*flow,所以常规套模板spfa无法得到最小费用 观察到每条边流量上限只有5,则可以把一条流量为f的边拆成f条流量为1的边,每条边费用是a*(2*i-1)(1<=i<=f) #include <iostream> #include <cstring> #include <cstdio> #includ

HDU 1533 Going Home(最小费用流)

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