1. 程式人生 > >(最小費用流)hdu 6118(2017百度之星初賽B 1005) 度度熊的交易計劃

(最小費用流)hdu 6118(2017百度之星初賽B 1005) 度度熊的交易計劃

ios rsh des pty rank tom mis 註意 pan

度度熊的交易計劃

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 }

(最小費用流)hdu 6118(2017百度之星初賽B 1005) 度度熊的交易計劃