(最小费用流)hdu 6118(2017百度之星初赛B 1005) 度度熊的交易计划

度度熊的交易计划

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 260    Accepted Submission(s): 83

Problem Description

度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题:

喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区。

由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但是最多生产b[i]个。

同样的,由于每个片区的购买能力的区别,第i个片区也能够以c[i]的价格出售最多d[i]个物品。

由于这些因素,度度熊觉得只有合理的调动物品,才能获得最大的利益。

据测算,每一个商品运输1公里,将会花费1元。

那么喵哈哈村最多能够实现多少盈利呢?

Input

本题包含若干组测试数据。
每组测试数据包含:
第一行两个整数n,m表示喵哈哈村由n个片区、m条街道。
接下来n行,每行四个整数a[i],b[i],c[i],d[i]表示的第i个地区,能够以a[i]的价格生产,最多生产b[i]个,以c[i]的价格出售,最多出售d[i]个。
接下来m行,每行三个整数,u[i],v[i],k[i],表示该条公路连接u[i],v[i]两个片区,距离为k[i]

可能存在重边,也可能存在自环。

满足:
1<=n<=500,
1<=m<=1000,
1<=a[i],b[i],c[i],d[i],k[i]<=1000,
1<=u[i],v[i]<=n

Output

输出最多能赚多少钱。

Sample Input

2 1
5 5 6 1
3 5 7 7
1 2 1

Sample Output

23

Source

2017"百度之星"程序设计大赛 - 初赛(B)

恰当的建图之后就是个裸的最小费用流(当然,由于求的是最大盈利,值乘-1进行计算)了。将每个点拆成3个,分别为: 由源点连向的点(边cost=a[i],cap=b[i]) 由第一种点(对应原图中下标设为i)连向的“入点”(对应原图中下标设为j)(cost=-(c[j]-dis[i][j]),cap=a[i])(其中dis[i][j]为i到j的最短路,事先需要floyd跑一边求一下) 由于每个点出售的数量是有限制的,故第三种点为第二种点一一对应连接的(cost=0,cap=d[i])第三种点再连向汇点。

不过需要注意的是,这样建的图并不一定是满流(因为有的地方可以不生产),故为了保证最小费用流中的满流条件,再增加一个“超级源点”、“超级汇点”,分别与原本的源点、汇点相连,并增加一条从原本的源点连向汇点的cost=0,cap=INF的边。

建完图之后直接进行最小费用流即可。

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <set>
  6 #include <map>
  7 #include <string>
  8 #include <cstring>
  9 #include <stack>
 10 #include <queue>
 11 #include <cmath>
 12 #include <ctime>
 13 #include<bitset>
 14 #include <utility>
 15 using namespace std;
 16 #define REP(I,N) for (I=0;I<N;I++)
 17 #define rREP(I,N) for (I=N-1;I>=0;I--)
 18 #define rep(I,S,N) for (I=S;I<N;I++)
 19 #define rrep(I,S,N) for (I=N-1;I>=S;I--)
 20 #define FOR(I,S,N) for (I=S;I<=N;I++)
 21 #define rFOR(I,S,N) for (I=N;I>=S;I--)
 22 #define rank rankk
 23 #define DFT FFT
 24 typedef unsigned long long ull;
 25 typedef long long ll;
 26 //const int INF=0x3f3f3f3f;
 27 const ll INFF=0x3f3f3f3f3f3f3f3fll;
 28 //const ll M=1e9+7;
 29 const ll maxn=2e5+7;
 30 //const int MAXN=1005;
 31 const int MAX=1e6+5;
 32 const int MAX_N=MAX;
 33 //const int N=55;
 34 const ll MOD=1e9+7;
 35 //const double eps=0.00000001;
 36 int gcd(int a,int b){return b?gcd(b,a%b):a;}
 37 template<typename T>inline T abs(T a) {return a>0?a:-a;}
 38 inline ll powMM(ll a,ll b,ll M){
 39     ll ret=1;
 40     a%=M;
 41 //    b%=M;
 42     while (b){
 43         if (b&1) ret=ret*a%M;
 44         b>>=1;
 45         a=a*a%M;
 46     }
 47     return ret;
 48 }
 49 void open()
 50 {
 51     freopen("t.txt","r",stdin);
 52     freopen("out.txt","w",stdout);
 53 }
 54
 55 const int MAXN = 10000;
 56 const int MAXM = 1000000;
 57 const int INF = 0x3f3f3f3f;
 58 struct Edge
 59 {
 60 int to,next,cap,flow,cost;
 61 }edge[MAXM];
 62 int head[MAXN],tol;
 63 int pre[MAXN],dis[MAXN];
 64 bool vis[MAXN];
 65 int N;//节点总个数,节点编号从0~N-1
 66 void init(int n)
 67 {
 68 N = n;
 69 tol = 0;
 70 memset(head,-1,sizeof(head));
 71 }
 72 void addedge(int u,int v,int cap,int cost)
 73 {
 74 edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++;
 75 }
 76 bool spfa(int s,int t)
 77 {
 78 queue<int>q;
 79 for(int i = 0;i < N;i++)
 80 {
 81 dis[i] = INF; vis[i] = false; pre[i] = -1;
 82 }
 83 dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty())
 84 {
 85 int u = q.front(); q.pop();
 86 vis[u] = false;
 87 for(int i = head[u]; i != -1;i = edge[i].next)
 88 {
 89 int v = edge[i].to;
 90
 91
 92 if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost )
 93 {
 94 dis[v] = dis[u] + edge[i].cost; pre[v] = i;
 95 if(!vis[v])
 96 {
 97 vis[v] = true; q.push(v);
 98 }
 99 }
100 }
101 }
102 if(pre[t] == -1)return false; else return true;
103 }
104 //返回的是最大流,cost存的是最小费用
105 int minCostMaxflow(int s,int t,int &cost)
106 {
107 int flow = 0; cost = 0; while(spfa(s,t))
108 {
109 int Min = INF;
110 for(int i = pre[t];i != -1;i = pre[edge[i^1].to])
111 {
112 if(Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow;
113 }
114 for(int i = pre[t];i != -1;i = pre[edge[i^1].to])
115 {
116 edge[i].flow += Min; edge[i^1].flow -= Min;
117 cost += edge[i].cost * Min;
118 }
119 flow += Min;
120 }
121 return flow;
122 }
123 int n,m;
124 int diss[505][505];
125 int a[505],b[505],c[505],d[505];
126 int V;//顶点数
127 void warshall_floyd()
128 {
129     for(int k=1;k<=V;k++)
130         for(int i=1;i<=V;i++)
131             for(int j=1;j<=V;j++)
132                 diss[i][j]=min(diss[i][j],diss[i][k]+diss[k][j]);
133 }
134 int main()
135 {
136     while(~scanf("%d%d",&n,&m))
137     {
138         memset(diss,-1,sizeof(diss));
139         for(int i=1;i<=n;i++)
140             scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
141         for(int i=1;i<=n;i++)
142             for(int j=1;j<=n;j++)
143                 diss[i][j]=(int)1e9;
144         for(int i=1;i<=n;i++)
145             diss[i][i]=0;
146         for(int i=1;i<=m;i++)
147         {
148             int x,y,z;
149             scanf("%d%d%d",&x,&y,&z);
150             if(x==y)
151                 continue;
152             diss[x][y]=diss[y][x]=min(z,diss[x][y]);
153         }
154         V=n;
155         warshall_floyd();
156         init(3*n+4);
157         for(int i=1;i<=n;i++)
158             addedge(0,i,b[i],a[i]);
159         for(int i=1;i<=n;i++)
160         {
161             for(int j=1;j<=n;j++)
162             {
163                 if(diss[i][j]!=-1&&c[j]>=a[i]+diss[i][j])
164                     addedge(i,j+n,b[i],-(c[j]-diss[i][j]));
165             }
166         }
167         for(int i=1;i<=n;i++)
168             addedge(i+n,i+2*n,d[i],0);
169         for(int i=1;i<=n;i++)
170             addedge(i+2*n,3*n+1,d[i],0);
171         addedge(3*n+2,0,INF,0);
172         addedge(3*n+1,3*n+3,INF,0);
173         addedge(0,3*n+1,INF,0);
174         int co;
175         int an=minCostMaxflow(3*n+2,3*n+3,co);
176         printf("%d\n",-co);
177     }
178 }
时间: 2024-10-11 01:44:24

(最小费用流)hdu 6118(2017百度之星初赛B 1005) 度度熊的交易计划的相关文章

HDU 6118 2017百度之星初赛B 度度熊的交易计划(费用流)

度度熊的交易计划 Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 254    Accepted Submission(s): 80 Problem Description 度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题: 喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区. 由于生产能力的区别,第i个片

2017百度之星资格赛 1003:度度熊与邪恶大魔王(DP)

.navbar-nav > li.active > a { background-image: none; background-color: #058; } .navbar-inverse #navbar > .navbar-nav > li > a:hover, .navbar-inverse #navbar > .navbar-nav > li > a:focus { background-image: none; background-color:

HDU 6119 2017百度之星初赛B 小小粉丝度度熊 (二分)

小小粉丝度度熊 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 197    Accepted Submission(s): 78 Problem Description 度度熊喜欢着喵哈哈村的大明星——星星小姐. 为什么度度熊会喜欢星星小姐呢? 首先星星小姐笑起来非常动人,其次星星小姐唱歌也非常好听. 但这都不是最重要的,最重要的是,星

2017&quot;百度之星&quot;程序设计大赛 - 资格赛-度度熊与邪恶大魔王(dp+后缀最小值)

度度熊与邪恶大魔王 思路:由于防御和血量的范围很小,所以暴力枚举出对于每种防御造成的每种伤害所需的最小花费,最后只需在伤害大于等于血量的情况下再找到最小花费(这个只需要后缀最小值预处理一下就可以了) 状态:dp[i][j]表示对防御为i的怪兽造成伤害为j的所需最小晶石花费. 状态转移方程:dp[i][j]=min(dp[i][j],dp[i][j-t])(t表示每种技能造成的伤害,t=p-i,t≥0) 代码1: #include<bits/stdc++.h> using namespace s

2017&quot;百度之星&quot;程序设计大赛 - 资格赛 度度熊的王国战略

度度熊的王国战略 度度熊国王率领着喵哈哈族的勇士,准备进攻哗啦啦族. 哗啦啦族是一个强悍的民族,里面有充满智慧的谋士,拥有无穷力量的战士. 所以这一场战争,将会十分艰难. 为了更好的进攻哗啦啦族,度度熊决定首先应该从内部瓦解哗啦啦族. 第一步就是应该使得哗啦啦族内部不能同心齐力,需要内部有间隙. 哗啦啦族一共有n个将领,他们一共有m个强关系,摧毁每一个强关系都需要一定的代价. 现在度度熊命令你需要摧毁一些强关系,使得内部的将领,不能通过这些强关系,连成一个完整的连通块,以保证战争的顺利进行. 请

hdu 6118 度度熊的交易计划(可行费用流)

题目链接:hdu 6118 度度熊的交易计划 题意: 中文,说的很清楚了. 题解: 对着输入建一些图,跑一下可行费用流就行了,即当费用为正的时候就不跑了,这样就先满足了费用最小. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 using namespace std; 4 5 namespace MCMF 6 { 7 const int N=1e5+7,inf=1e9+7; 8 int u[

2017百度之星初赛(A)1001,1005,1006解题报告

1001 小C的倍数问题 纯签到题,求p-1的因数个数,暴力枚举即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 ios::sync_with_stdio(false); 6 int t,p,cnt,n,num; 7 cin>>t; 8 while(t--) 9 { 10 cnt=0; 11 cin>>p; 12 n=p-1; 13 for(int i=1;i*i<=n;+

2017百度之星初赛

1001 小C的倍数问题 Accepts: 1990 Submissions: 4931 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Description 根据小学数学的知识,我们知道一个正整数x是3的倍数的条件是x每一位加起来的和是3的倍数.反之,如果一个数每一位加起来是3的倍数,则这个数肯定是3的倍数. 现在给定进制P,求有多少个B满足P进制下,一个正整数是

【HDOJ6118】度度熊的交易计划(最小费用流)

题意: 度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题: 喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区. 由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但是最多生产b[i]个. 同样的,由于每个片区的购买能力的区别,第i个片区也能够以c[i]的价格出售最多d[i]个物品. 由于这些因素,度度熊觉得只有合理的调动物品,才能获得最大的利益. 据测算,每一个商品运输1公里,将会花费1元. 那么喵哈哈村最多能够实现多少盈利呢? 1<=n<=500,