日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[费用流专题]Going Home,Minimum Cost,工作安排

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [费用流专题]Going Home,Minimum Cost,工作安排 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • T1:Going Home
    • 題目
    • 題解
    • CODE
  • T2:Minimum Cost
    • 題目
    • 題解
    • CODE
  • T3:工作安排
    • 題解
    • CODE

T1:Going Home

題目

On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man.

Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a ‘.’ means an empty space, an ‘H’ represents a house on that point, and am ‘m’ indicates there is a little man on that point.

You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.
Input
There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of 'H’s and 'm’s on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.
Output
For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.
Sample Input
2 2
.m
H.
5 5
HH…m



mm…H
7 8
…H…
…H…
…H…
mmmHmmmm
…H…
…H…
…H…
0 0
Sample Output
2
10
28

題解

簡單題意就是一張圖,HHH表示一間屋子,mmm表示一個人,現在每個人要走到一間屋子里,消耗的費用為兩點之間的距離,求每個都有一個房子的最小耗費


是一道很裸的費用流問題,這里本蒟蒻選擇了EK+SPFAEK+SPFAEK+SPFA
我們考慮建圖問題,先建一個超級源點s和一個超級匯點t,然后將所有房子HHH和s建邊,容量定義為1,邊權免費,同理把所有人在的mmm和t建邊,容量為1,邊權免費
最后的邊權決定于房子和人的搭配,這個邊權就是矩陣里面兩個點之間的距離,容量仍然是1,因為一人一間房

CODE

#include <queue> #include <cmath> #include <vector> #include <cstdio> #include <cstring> using namespace std; #define INF 1e9 #define MAXM 1000005 #define MAXN 100005 struct node {int v, w, next, c, flow; }edge[MAXM]; queue < int > q; vector < pair < int, int > > h, m; //處理出每一個房子和人所在的位置,第一關鍵字是行,第二關鍵字是列 int cnt, N, M, s, t; int head[MAXN], dis[MAXN], pre[MAXN]; bool vis[MAXN];void add ( int x, int y, int flow, int fi ) {edge[cnt].next = head[x];edge[cnt].v = y;edge[cnt].w = fi;edge[cnt].c = flow;edge[cnt].flow = 0;head[x] = cnt ++; }bool spfa () {memset ( vis, 0, sizeof ( vis ) ); memset ( dis, 0x7f, sizeof ( dis ) );memset ( pre, -1, sizeof ( pre ) );while ( ! q.empty() )q.pop();q.push( s );dis[s] = 0;vis[s] = 1;while ( ! q.empty() ) {int u = q.front();q.pop();vis[u] = 0;for ( int i = head[u];i != -1;i = edge[i].next ) {int v = edge[i].v;if ( dis[v] > dis[u] + edge[i].w && edge[i].c > edge[i].flow ) {dis[v] = dis[u] + edge[i].w;pre[v] = i;if ( ! vis[v] ) {q.push( v );vis[v] = 1;}}}} return pre[t] != -1; }void MCMF ( int &maxflow, int &mincost ) {maxflow = mincost = 0;while ( spfa() ) {int MIN = INF;for ( int i = pre[t];i != -1;i = pre[edge[i ^ 1].v] )MIN = min ( MIN, edge[i].c - edge[i].flow );for ( int i = pre[t];i != -1;i = pre[edge[i ^ 1].v] ) {edge[i].flow += MIN;edge[i ^ 1].flow -= MIN;mincost += MIN * edge[i].w;}maxflow += MIN;} }int Fabs ( int x ) {if ( x < 0 )return -x;return x; }int main() {while ( scanf ( "%d %d", &N, &M ) ) {if ( N == 0 && M == 0 )return 0;memset ( head, -1, sizeof ( head ) );cnt = 0;h.clear();m.clear(); for ( int i = 1;i <= N;i ++ ) {getchar();for ( int j = 1;j <= M;j ++ ) {char ch;scanf ( "%c", &ch );if ( ch == 'H' )h.push_back( make_pair ( i, j ) );if ( ch == 'm' )m.push_back ( make_pair ( i, j ) );}}s = 0;t = N * M + 1;for ( int i = 0;i < h.size();i ++ ) {//與超級源點建邊add ( s, ( h[i].first - 1 ) * M + h[i].second, 1, 0 );add ( ( h[i].first - 1 ) * M + h[i].second, s, 0, 0 );for ( int j = 0;j < m.size();j ++ ) {//屋子與人建邊,算是一種hash吧,畢竟每一個人和每一件房子都是獨一無二的add ( ( h[i].first - 1 ) * M + h[i].second, ( m[j].first - 1 ) * M + m[j].second, 1, Fabs ( h[i].first - m[j].first ) + Fabs ( h[i].second - m[j].second ) );add ( ( m[j].first - 1 ) * M + m[j].second, ( h[i].first - 1 ) * M + h[i].second, 0, - Fabs ( h[i].first - m[j].first ) - Fabs ( h[i].second - m[j].second ) );}}//與超級匯點建邊for ( int i = 0;i < m.size();i ++ ) {add ( ( m[i].first - 1 ) * M + m[i].second, t, 1, 0 );add ( t, ( m[i].first - 1 ) * M + m[i].second, 0, 0 );}int maxflow, mincost;MCMF ( maxflow, mincost );printf ( "%d\n", mincost );}return 0; }

T2:Minimum Cost

題目

Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy has M supply places (marked from 1 to M), each provides K different kinds of goods (marked from 1 to K). Once shopkeepers order goods, Dearboy should arrange which supply place provide how much amount of goods to shopkeepers to cut down the total cost of transport.

It’s known that the cost to transport one unit goods for different kinds from different supply places to different shopkeepers may be different. Given each supply places’ storage of K kinds of goods, N shopkeepers’ order of K kinds of goods and the cost to transport goods for different kinds from different supply places to different shopkeepers, you should tell how to arrange the goods supply to minimize the total cost of transport.
Input
The input consists of multiple test cases. The first line of each test case contains three integers N, M, K (0 < N, M, K < 50), which are described above. The next N lines give the shopkeepers’ orders, with each line containing K integers (there integers are belong to [0, 3]), which represents the amount of goods each shopkeeper needs. The next M lines give the supply places’ storage, with each line containing K integers (there integers are also belong to [0, 3]), which represents the amount of goods stored in that supply place.

Then come K integer matrices (each with the size N * M), the integer (this integer is belong to (0, 100)) at the i-th row, j-th column in the k-th matrix represents the cost to transport one unit of k-th goods from the j-th supply place to the i-th shopkeeper.

The input is terminated with three "0"s. This test case should not be processed.
Output
For each test case, if Dearboy can satisfy all the needs of all the shopkeepers, print in one line an integer, which is the minimum cost; otherwise just output “-1”.
Sample Input
1 3 3
1 1 1
0 1 1
1 2 2
1 0 1
1 2 3
1 1 1
2 1 1

1 1 1
3
2
20

0 0 0
Sample Output
4
-1

題解

其實這道題有點考語文,輸入太**

我們考慮建一個超級源點和超級匯點,
在源點和店主的需求之間建一條邊,沒有中間商賺差價,容量自然就是店主的訂單量,
同理在供應地點和超級匯點之間建一條邊,也沒有中間商賺差價,容量為供應地點生產的產品數;
最后就是店主與供應地點之間的建邊,因為有kkk種不同的商品,所以一個供應地點跟一個店主之間的成本也會隨著kkk的不一樣而改變,兩個解決辦法

1.把一個供應地點拆成kkk個彼此獨立的供應柜臺,專門只銷售一種類型的
由上面我們就可以發現,柜臺之間是彼此獨立的,互不影響,所以我們就有了第二種解決方案
2.把費用流拆成kkk次一種商品的費用流,每次費用流都只處理一種商品,這樣建邊就不那么冗長

CODE

#include <queue> #include <cmath> #include <vector> #include <cstdio> #include <cstring> using namespace std; #define INF 1e9 #define MAXN 100 struct node {int v, w, next, c, flow; }edge[MAXN * MAXN]; queue < int > q; int cnt, n, m, k, s, t; int head[MAXN], dis[MAXN], pre[MAXN], need[MAXN][MAXN], num[MAXN][MAXN], matrix[MAXN][MAXN][MAXN]; bool vis[MAXN];void add ( int x, int y, int flow, int cost ) {edge[cnt].next = head[x];edge[cnt].v = y;edge[cnt].w = cost;edge[cnt].c = flow;edge[cnt].flow = 0;head[x] = cnt ++; }bool spfa () {memset ( vis, 0, sizeof ( vis ) ); memset ( dis, 0x7f, sizeof ( dis ) );memset ( pre, -1, sizeof ( pre ) );while ( ! q.empty() )q.pop();q.push( s );dis[s] = 0;vis[s] = 1;while ( ! q.empty() ) {int u = q.front();q.pop();vis[u] = 0;for ( int i = head[u];~ i;i = edge[i].next ) {int v = edge[i].v;if ( dis[v] > dis[u] + edge[i].w && edge[i].c > edge[i].flow ) {dis[v] = dis[u] + edge[i].w;pre[v] = i;if ( ! vis[v] ) {q.push( v );vis[v] = 1;}}}} return pre[t] != -1; }void MCMF ( int &maxflow, int &mincost ) {maxflow = mincost = 0;while ( spfa() ) {int MIN = INF;for ( int i = pre[t];~ i;i = pre[edge[i ^ 1].v] )MIN = min ( MIN, edge[i].c - edge[i].flow );for ( int i = pre[t];~ i;i = pre[edge[i ^ 1].v] ) {edge[i].flow += MIN;edge[i ^ 1].flow -= MIN;mincost += MIN * edge[i].w;}maxflow += MIN;} }int main() {while ( scanf ( "%d %d %d", &n, &m, &k ) != EOF ) {if ( n == 0 && m == 0 && k == 0 )return 0;int sum = 0;for ( int i = 1;i <= n;i ++ )for ( int j = 1;j <= k;j ++ ) {scanf ( "%d", &need[i][j] );sum += need[i][j];}for ( int i = 1;i <= m;i ++ )for ( int j = 1;j <= k;j ++ )scanf ( "%d", &num[i][j] );for ( int i = 1;i <= k;i ++ )for ( int j = 1;j <= n;j ++ )for ( int p = 1;p <= m;p ++ )scanf ( "%d", &matrix[i][j][p] );s = 0;t = n + m + 1;int result = 0, Flow = 0;for ( int i = 1;i <= k;i ++ ) {memset ( head, -1, sizeof ( head ) );cnt = 0;for ( int j = 1;j <= n;j ++ ) {add ( s, j, need[j][i], 0 );add ( j, s, 0, 0 );}for ( int j = 1;j <= n;j ++ )for ( int p = 1;p <= m;p ++ ) {add ( j, n + p, num[p][i], matrix[i][j][p] );add ( n + p, j, 0, -matrix[i][j][p] );}for ( int j = 1;j <= m;j ++ ) {add ( j + n, t, num[j][i], 0 );add ( t, j + n, 0, 0 );}int mincost, maxflow;MCMF ( maxflow, mincost );result += mincost;Flow += maxflow;}if ( Flow == sum )printf ( "%d\n", result );elseprintf ( "-1\n" );}return 0; }

T3:工作安排

你的公司接到了一批訂單。訂單要求你的公司提供n類產品,產品被編號為1n1~n1?n,其中第i類產品共需要Ci件。公司共有m名員工,員工被編號為1m1~m1?m員工能夠制造的產品種類有所區別。一件產品必須完整地由一名員工制造,不可以由某名員工制造一部分配件后,再轉交給另外一名員工繼續進行制造。

我們用一個由0和1組成的m*n的矩陣A來描述每名員工能夠制造哪些產品。矩陣的行和列分別被編號為1m1~m1?m1n1~n1?n,Ai,j為1表示員工i能夠制造產品j,為0表示員工i不能制造產品j。

如果公司分配了過多工作給一名員工,這名員工會變得不高興。我們用憤怒值來描述某名員工的心情狀態。憤怒值越高,表示這名員工心情越不爽,憤怒值越低,表示這名員工心情越愉快。員工的憤怒值與他被安排制造的產品數量存在某函數關系,鑒于員工們的承受能力不同,不同員工之間的函數關系也是有所區別的。

對于員工i,他的憤怒值與產品數量之間的函數是一個Si+1段的分段函數。當他制造第1Ti1~Ti1?Ti,1件產品時,每件產品會使他的憤怒值增加Wi,1,當他制造第Ti,1+1Ti,2Ti,1+1~Ti,2Ti,1+1?Ti,2件產品時,每件產品會使他的憤怒值增加Wi,2……Wi,2……Wi,2為描述方便,設Ti,0=0,Ti,si+1=+∞,Ti,0=0,Ti,si+1=+∞,Ti,0=0,Ti,si+1=+那么當他制造第Ti,j?1+1Ti,jTi,j-1+1~Ti,jTi,j?1+1?Ti,j件產品時,每件產品會使他的憤怒值增加Wi,j,1≤j≤Si+1Wi,j, 1≤j≤Si+1Wi,j1jSi+1

你的任務是制定出一個產品的分配方案,使得訂單條件被滿足,并且所有員工的憤怒值之和最小。由于我們并不想使用Special Judge,也為了使選手有更多的時間研究其他兩道題目,你只需要輸出最小的憤怒值之和就可以了。

Input
第一行包含兩個正整數m和n,分別表示員工數量和產品的種類數;
第二行包含n 個正整數,第i個正整數為Ci;

以下m行每行n 個整數描述矩陣A;
下面m個部分,第i部分描述員工i的憤怒值與產品數量的函數關系。每一部分由三行組成:第一行為一個非負整數Si,第二行包含Si個正整數,其中第j個正整數為Ti,j,如果Si=0那么輸入將不會留空行(即這一部分只由兩行組成)。第三行包含Si+1個正整數,其中第j個正整數為Wi,j。

Output
僅輸出一個整數,表示最小的憤怒值之和。

Sample Input
2 3
2 2 2
1 1 0
0 0 1
1
2
1 10
1
2
1 6
Sample Output
24

Hint

題解

考語文啊~~

這道題的提示,保證了憤怒值是單調遞增的,就是費用流的關鍵,給我們的解題提供了保障
我們考慮對于一堆產品,第一階段的產品生產的憤怒值一定小于后面階段的產品生產的憤怒值,那么我們把憤怒值當成費用,我們一定會先選擇第一階段的流量邊再選擇第二階段的流量邊,這樣就不會出現直接生產第二階段導致我們的出錯


那么我們就建一個超級源點和超級匯點,源點和員工之間連邊,員工和產品之間連邊,邊數就是員工的憤怒階段+1+1+1,最后一段是infinfinf,每個階段對應的容量就是該階段的產品數,費用就是憤怒值;最后是產品和匯點之間連邊

CODE

#include <queue> #include <cmath> #include <vector> #include <cstdio> #include <cstring> using namespace std; #define INF 1e9 #define LL long long #define MAXN 1005 struct node {int v, next;LL w, c, flow; }edge[MAXN * MAXN]; queue < int > q; int cnt, n, m, s, t; int head[MAXN], pre[MAXN], C[MAXN], a[MAXN][MAXN], b[MAXN]; bool vis[MAXN]; LL dis[MAXN];void add ( int x, int y, LL flow, LL cost ) {edge[cnt].next = head[x];edge[cnt].v = y;edge[cnt].w = cost;edge[cnt].c = flow;edge[cnt].flow = 0;head[x] = cnt ++; }bool spfa () {memset ( vis, 0, sizeof ( vis ) ); memset ( dis, 0x7f, sizeof ( dis ) );memset ( pre, -1, sizeof ( pre ) );while ( ! q.empty() )q.pop();q.push( s );dis[s] = 0;vis[s] = 1;while ( ! q.empty() ) {int u = q.front();q.pop();vis[u] = 0;for ( int i = head[u];~ i;i = edge[i].next ) {int v = edge[i].v;if ( dis[v] > dis[u] + edge[i].w && edge[i].c > edge[i].flow ) {dis[v] = dis[u] + edge[i].w;pre[v] = i;if ( ! vis[v] ) {q.push( v );vis[v] = 1;}}}} return pre[t] != -1; }void MCMF ( LL &maxflow, LL &mincost ) {maxflow = mincost = 0;while ( spfa() ) {LL MIN = INF;for ( int i = pre[t];~ i;i = pre[edge[i ^ 1].v] )MIN = min ( MIN, edge[i].c - edge[i].flow );for ( int i = pre[t];~ i;i = pre[edge[i ^ 1].v] ) {edge[i].flow += MIN;edge[i ^ 1].flow -= MIN;mincost += MIN * edge[i].w;}maxflow += MIN;} }int main() {memset ( head, -1, sizeof ( head ) );scanf ( "%d %d", &m, &n );s = 0;t = n + m + 1;for ( int i = 1;i <= n;i ++ ) {scanf ( "%d", &C[i] );add ( s, i, C[i], 0 );add ( i, s, 0, 0 );}for ( int i = 1;i <= m;i ++ )for ( int j = 1;j <= n;j ++ ) {scanf ( "%d", &a[i][j] );if ( a[i][j] ) {add ( j, i + n, INF, 0 );add ( i + n, j, 0, 0 );}}for ( int i = 1;i <= m;i ++ ) {int S;scanf ( "%d", &S );for ( int j = 1;j <= S;j ++ )scanf ( "%d", &b[j] );b[S + 1] = INF;for ( int j = 1;j <= S + 1;j ++ ) {int w;scanf ( "%d", &w );add ( i + n, t, ( b[j] - b[j - 1] ), w );add ( t, i + n, 0, -w );}}LL maxflow, mincost;MCMF ( maxflow, mincost );printf ( "%lld", mincost );return 0; }

總結

以上是生活随笔為你收集整理的[费用流专题]Going Home,Minimum Cost,工作安排的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。