网络流专题(最大流、最小费用流、最小割、Dinic、EK、Spafa算法)

Dining
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 27910 Accepted: 12237

Description

Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.

Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.

Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.

Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).

Input

Line 1: Three space-separated integers: N, F, and D
Lines 2…N+1: Each line i starts with a two integers Fi and Di, the number of dishes that cow i likes and the number of drinks that cow i likes. The next Fi integers denote the dishes that cow i will eat, and the Di integers following that denote the drinks that cow i will drink.

Output

Line 1: A single integer that is the maximum number of cows that can be fed both food and drink that conform to their wishes

Sample Input

4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3

Sample Output

3
Hint

One way to satisfy three cows is:
Cow 1: no meal
Cow 2: Food #2, Drink #2
Cow 3: Food #1, Drink #1
Cow 4: Food #3, Drink #3
The pigeon-hole principle tells us we can do no better since there are only three kinds of food or drink. Other test data sets are more challenging, of course.
题目大意:
n n n只牛, f f f个食物, d d d个饮料。每只牛有喜欢吃的食物和饮料(题目给你列表),问你最多有多少头牛可以吃到自己想要的食物。
思路:
我们只需要限制每个食物和饮料只能被选一次,然后跑最大流就行了。
一开始我是这样建图的:
在这里插入图片描述

但是这样会有一个问题:
在这里插入图片描述
饮料保证了只会出现一次(因为连向汇点),但是食物会出现多次,所以不满足题目要求。
我们要是的食物和饮料有且仅有被选择一次,我们可以这样建图:
在这里插入图片描述
把一头牛拆成两个点,一边连食物,一边连饮料,这样可以保证食物和饮料只会被选择一次,然后快乐地跑最大流就行了。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<stdio.h>
#include<cstring>
using namespace std;

int G[1010][1010];
int n,f,d;
int pre[1010];
int flow[1010];
int bfs(int s,int t){
    queue<int>st;
    st.push(s);
    memset(pre,-1,sizeof(pre));
    pre[s] = 0,flow[s] = 1e9;
    while(!st.empty()){
        int u = st.front();st.pop();
        if(u == t)break;
        for(int v = 1; v <= t; v++){
            if(G[u][v] > 0 && pre[v] == -1){
                pre[v] = u;
                flow[v] = min(flow[u],G[u][v]);
                st.push(v);
            }
        }
    }
    if(pre[t] == -1)return -1;
    else return flow[t];
}
void EK(int s,int t){
    int delta = 0,tot = 0;
    while(1){
        delta = bfs(s,t);
        if(delta == -1)break;
        int p = t;
        while(p != s){
            G[pre[p]][p] -= delta;
            G[p][pre[p]] += delta;
            p = pre[p];
        }
        tot += delta;
    }
    printf("%d\n",tot);
}
void solved(){
    while(scanf("%d%d%d",&n,&f,&d)!=EOF){
        memset(G,0,sizeof(G));
        memset(flow,0,sizeof(flow));
        for(int i = 1; i <= n; i++){
            G[i][n + i] = 1;
            int fi,di;scanf("%d%d",&fi,&di);
            for(int j = 1; j <= fi; j++){
                int x;scanf("%d",&x);
                G[2 * n + x][i] = 1;
            }
            for(int j = 1; j <= di; j++){
                int x;scanf("%d",&x);
                G[n + i][2 * n + f + x] = 1;
            }
        }
        int s = 0,t = n * 2 + f + d + 1;
        for(int i = 2 * n + 1; i <= 2 * n + f; i++){
            G[0][i] = 1;
        }
        for(int i = 2 * n + f + 1; i <= 2 * n + f + d; i++){
            G[i][t] = 1;
        }
        EK(s,t);
    }
}
int main(){
    solved();
    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目大意:
n n n个人,有 m m m个星球,每个人有想去的星球,每个星球有容纳人数的上限,问你能不能让每个人都可以去自己想去的星球。
思路:
很明显的最大流,源点-人-星球-汇点,源点与人之间的流量为1,人与星球的流量为1,星球与汇点的容量为上限,就可以了,一开始我是这么想的,不过 n = 1 e 5 , m = 10 , n , m n = 1e5,m = 10,n,m n=1e5,m=10,n,m连边就会有 1 e 6 1e6 1e6,直接超时,所以要状态压缩(就是用二进制处理加快速度),因为人的点太多了,但是星球只有10,对于每个星期选与不选一共有 1024 1024 1024种选择,所以我们直接把人的点换成 1024 1024 1024中状态,然后源点-状态-星球-汇点建图,源点与状态之间是该状态有多少人数,状态与星球是该点二进制拆分与对应星球建立一条流量为1的边,星球与汇点是改星球上限,然后跑最大流,看是否满流即可。
我的代码 0 − 1023 0-1023 01023是状态数, 1024 1024 1024是源点, 1024 + m 1024+m 1024+m是星球, 1024 + m + 1 1024+m+1 1024+m+1是汇点。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<stdio.h>
#include<cstring>
using namespace std;
typedef long long int ll;

const int maxn = 2e6;
struct edge{
    int v,f,next;
}e[maxn];
int head[maxn],tot = 1;
void add(int u,int v,int f){
    e[++tot].f = f;
    e[tot].v = v;
    e[tot].next = head[u];
    head[u] = tot;
}
int dep[maxn];
int now[maxn];
bool bfs(int s,int t){
    memset(dep,-1,sizeof(dep));
    queue<int>st;st.push(s);
    dep[s] = 0;
    now[s] = head[s];
    while(!st.empty()){
        int u = st.front();st.pop();
        for(int i = head[u]; i; i = e[i].next){
            int v = e[i].v;
            if(dep[v] == -1 && e[i].f > 0){
                dep[v] = dep[u] + 1;
                st.push(v);
                now[v] = head[v];
                if(v == t)return true;
            }
        }
    }
    return false;
}
int dfs(int u,int flow,int t){
    if(u == t)return flow;
    int rest = 0;
    for(int i = now[u]; i && flow; i = e[i].next){
        now[u] = i;
        int v = e[i].v;
        if(dep[v] == dep[u] + 1 && e[i].f > 0){
            int temp = dfs(v,min(flow,e[i].f),t);
            if(temp == 0)dep[v] = -1;
            flow -= temp;
            rest += temp;
            e[i].f -= temp;
            e[i ^ 1].f += temp;
        }
    }
    return rest;
}
void maxflow(int n,int s,int t){
    int ans = 0;
    while(bfs(s,t)){
        ans += dfs(s,1<<9,t);
    }
    if(ans == n)cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
}
int peo[1024];
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        tot = 1;
        memset(head,0,sizeof(head));
        memset(peo,0,sizeof(peo));
        int cnt = 0;
        for(int i = 1; i <= n; i++){
            int temp = 0;
            for(int j = 1; j <= m; j++){
                int x;scanf("%d",&x);
                if(x)
                temp |= (1 << (j - 1));
            }
            ++peo[temp];
        }
        int s = 1024,t = 1024 + m + 1;
        for(int i = 0; i <= 1023; i++){
            if(peo[i] > 0){
                add(s,i,peo[i]);
                add(i,s,0);
            }
        }
        for(int i = 0; i <= 1023; i++){
            if(peo[i] > 0){
                for(int j = 1; j <= 10 ;j++){
                    if(i & (1 << (j - 1))){
                        add(i,1024 + j,peo[i]);
                        add(1024 + j,i,0);
                    }
                }
            }
        }
        for(int i = 1; i <= m; i++){
            int x;scanf("%d",&x);
            add(1024 + i,t,x);
            add(t,1024 + i,0);
        }
        maxflow(n,s,t);
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述

题面大意:
给你一个矩阵,其中有 n n n个人和房子,每个房子只能容纳一个人,问你所有人到所有房子的最小花费是多少,一个上向上下左右移动一个单子花费1.
思路:
建图:源点-人-房子-汇点。
源点到人费用0,流量1,人到房子(枚举每个人到所有房子),费用为哈密顿值,流量为1,房子到汇点,流量1(因为一个房子只能容纳一个人),费用0.
然后跑最小费用流,求出所有费用的和即可。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<cmath>
#include<set>
#include<stdio.h>
#include<cstring>
using namespace std;

const int maxn = 2e5 + 10;
struct edge{
    int v,next,w,f;
}e[maxn];
int head[maxn],tot;
void add(int u,int v,int w,int f){
    e[++tot].v = v;
    e[tot].f = f;
    e[tot].w = w;
    e[tot].next = head[u];
    head[u] = tot;
}
char s[1000][1000];
int dis(pair<int,int>a,pair<int,int>b){
    return abs(a.first - b.first) + abs(a.second - b.second);
}
int pre[maxn];
bool vis[maxn];
int dist[maxn];
int flow[maxn];
bool spfa(int s,int t){
    memset(pre,-1,sizeof(pre));
    memset(vis,false,sizeof(vis));
    memset(dist,0x3f,sizeof(dist));
    queue<int>st;
    st.push(s);
    vis[s] = 1;dist[s] = 0;flow[s] = 1e9;
    while(!st.empty()){
        int u = st.front();st.pop();
        vis[u] = 0;
        for(int i = head[u]; i ; i = e[i].next){
            if(e[i].f <= 0)continue;
            int v = e[i].v;
            if(dist[v] > dist[u] + e[i].w){
                dist[v] = dist[u] + e[i].w;
                pre[v] = i;
                flow[v] = min(flow[u],e[i].f);
                if(vis[v] == 0){
                    st.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
    return dist[t] != 1061109567;
}
void mcmf(int s,int t){
    int ans = 0;
    while(spfa(s,t)){
        ans += dist[t];
        int p = t;
        while(p != s){
            e[pre[p]].f -= flow[t];
            e[pre[p] ^ 1].f += flow[t];
            p = e[pre[p] ^ 1].v;    
        }
    }
    printf("%d\n",ans);
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m) && (n || m)){
        int cnt = 0;
        tot = 1;
        memset(head,0,sizeof(head));
        vector<pair<int,int> >M,H;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                scanf(" %c",&s[i][j]);
                if(s[i][j] == 'H'){
                    cnt++;
                    H.push_back(make_pair(i,j));
                }
                if(s[i][j] == 'm'){
                    M.push_back(make_pair(i,j));
                }
            }
        }
        int s = 0, t = 2 * cnt + 1;
        for(int i = 0; i < M.size(); i++){
            add(s,i + 1,0,1);
            add(i + 1,s,0,0);
            for(int j = 0; j < H.size(); j++){
                add(i + 1,cnt + j + 1,dis(M[i],H[j]),1);
                add(cnt + j + 1,i + 1,-dis(M[i],H[j]),0);
            }
        }
        for(int i = 0; i < H.size(); i++){
            add(cnt + i + 1,t,0,1);
            add(t,cnt + i + 1,0,0);
        }
        mcmf(s,t);
    }
    return 0;
}

Island Transport

Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 17187 Accepted Submission(s): 5273

Problem Description

In the vast waters far far away, there are many islands. People are living on the islands, and all the transport among the islands relies on the ships.
  You have a transportation company there. Some routes are opened for passengers. Each route is a straight line connecting two different islands, and it is bidirectional. Within an hour, a route can transport a certain number of passengers in one direction. For safety, no two routes are cross or overlap and no routes will pass an island except the departing island and the arriving island. Each island can be treated as a point on the XY plane coordinate system. X coordinate increase from west to east, and Y coordinate increase from south to north.
  The transport capacity is important to you. Suppose many passengers depart from the westernmost island and would like to arrive at the easternmost island, the maximum number of passengers arrive at the latter within every hour is the transport capacity. Please calculate it.

Input

The first line contains one integer T (1<=T<=20), the number of test cases.
  Then T test cases follow. The first line of each test case contains two integers N and M (2<=N,M<=100000), the number of islands and the number of routes. Islands are number from 1 to N.
  Then N lines follow. Each line contain two integers, the X and Y coordinate of an island. The K-th line in the N lines describes the island K. The absolute values of all the coordinates are no more than 100000.
  Then M lines follow. Each line contains three integers I1, I2 (1<=I1,I2<=N) and C (1<=C<=10000) . It means there is a route connecting island I1 and island I2, and it can transport C passengers in one direction within an hour.
  It is guaranteed that the routes obey the rules described above. There is only one island is westernmost and only one island is easternmost. No two islands would have the same coordinates. Each island can go to any other island by the routes.

Output

For each test case, output an integer in one line, the transport capacity.

Sample Input

2
5 7
3 3
3 0
3 1
0 0
4 5
1 3 3
2 3 4
2 4 3
1 5 6
4 5 3
1 4 4
3 4 2
6 7
-1 -1
0 1
0 2
1 0
1 1
2 3
1 2 1
2 3 6
4 5 5
5 6 3
1 4 6
2 5 5
3 6 4

Sample Output
9
6
题面大意:
给你 n n n个点, m m m条边,最左边的点为源点,最右边的点为汇点,求最大流。
思路:模板题。。。。
不过要稍微优化一下dfs求最大流部分,具体看我代码(一个优化就行了)
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
#include<stdio.h>
using namespace std;

const int maxn = 1e5 + 10;
struct edge{
    int v,next,f;
}e[maxn << 1];
int head[maxn],tot;
void add(int u,int v,int f){
    e[++tot].f = f;
    e[tot].v = v;
    e[tot].next = head[u];
    head[u] = tot;
}
int dep[maxn];
bool bfs(int s,int t){
    queue<int>st;
    memset(dep,-1,sizeof(dep));
    st.push(s);dep[s] = 0;
    while(!st.empty()){
        int u = st.front();st.pop();
        for(int i = head[u]; i ; i = e[i].next){
            int v = e[i].v;
            if(dep[v] == -1 && e[i].f > 0){
                dep[v] = dep[u] + 1;
                st.push(v);
                if(v == t)return true;
            }
        }
    }
    return false;
}
int dfs(int u,int flow,int t){
    if(u == t)return flow;
    int rest = 0;
    for(int i = head[u]; i && flow ;i = e[i].next){
        int v = e[i].v;
        if((dep[v] == (dep[u] + 1)) && e[i].f > 0){
            int temp = dfs(v,min(flow,e[i].f),t);
            if(temp <= 0){//加一个这样的优化就过了。。。。
                dep[v] = -2;
                continue;
            }
            rest += temp;
            flow -= temp;
            e[i].f -= temp;
            e[i ^ 1].f += temp;
            if(!rest)break;//优化
        }
    }
    return rest;
}
void maxflow(int s,int t){
    int ans = 0;
    while(bfs(s,t)){
        ans += dfs(s,1e9,t);
    }
    printf("%d\n",ans);
}
void solved(){
    tot = 1;
    memset(head,0,sizeof(head));
    int n,m;scanf("%d%d",&n,&m);
    int x,y;scanf("%d%d",&x,&y);
    int minn = x;
    int maxx = x;
    int s,t;s = t = 1;
    for(int i = 2; i <= n; i++){
        scanf("%d%d",&x,&y);
        if(x < minn)
        {minn = x;s = i;}
        if(x > maxx)
        {maxx = x;t = i;}
    }
    for(int i = 1; i <= m; i++){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    maxflow(s,t);
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        solved();
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述
题面大意:
给你一张图,求使得它不连通的最小费用。
思路:
很显然求的是最小割点,最小割 = 最大流,所以建图跑最大流就行了。
把点拆开,边权为这个点的费用,然后建边(无向图),然后跑最大流就行了。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<stdio.h>
#include<cstring>
typedef long long int ll;
using namespace std;

const int maxn = 100010;
const int inf = 0x3f3f3f3f;
struct edge{
    int v,next,f;
}e[maxn];
int head[maxn],tot;
void add(int u,int v,int w){
	e[tot].v = v;
	e[tot].f = w;
	e[tot].next = head[u];
	head[u] = tot++;
}
int dep[maxn];
bool bfs(int s,int t){
    memset(dep,-1,sizeof(dep));
    dep[s] = 1;
    queue<int>st;
    st.push(s);
    while(!st.empty()){
        int u = st.front();st.pop();
        for(int i = head[u]; i ;i = e[i].next){
            int v = e[i].v;
            if(dep[v] == -1 && e[i].f > 0){
                dep[v] = dep[u] + 1;
                st.push(v);
                if(v == t)return true;
            }
        }
    }
    return false;
}
int dfs(int u,int flow,int t)
{
    if(u == t)return flow;
    int rest = 0;
    for(int i = head[u];i ;i = e[i].next){
        int v = e[i].v;
        if(dep[v] == dep[u] + 1 && e[i].f > 0){
            ll temp = dfs(v,min(flow,e[i].f),t);
            if(temp == 0)dep[v] = -1;//炸点优化
            rest += temp;//通过这个点流出去的流量
            flow -= temp;//这个点剩余流流
            e[i].f -= temp;
            e[i ^ 1].f += temp;
        }
    }
    if(!rest)dep[u]=-2;
    return rest;
}
void maxflow(int s,int t){
    int ans = 0;
    while(bfs(s,t)){
            ans += dfs(s,inf,t);
    }
    printf("%d\n",ans);
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(head,0,sizeof(head));
        tot = 2;
        int s,t;scanf("%d%d",&s,&t);
        t = t + n;
        for(int i = 1; i <= n; i++){
            int w;scanf("%d",&w);
            add(i,i + n,w);
            add(n + i,i,0);
        }
        for(int i = 1; i <= m; i++){
            int a,b;scanf("%d%d",&a,&b);
            add(a + n,b,inf);
            add(b,a + n,0); 
            add(b + n,a,inf);
            add(a,b + n,0);
        }
        maxflow(s,t);
    }
    return 0;
}
Minimum Cost

Time Limit: 4000MS Memory Limit: 65536K
Total Submissions: 20929 Accepted: 7362

Description

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
题面大意:
n n n个商家需要从 m m m个工厂进 k k k种货物,给定每个工厂每种货物的库存,每个商家对每种货物的需求量,和每个商家去每个工厂进每种货物需要的运费,问你最小运费。
思路:
一开始题面没看明白,看明白了之后发现就是 k k k次最小费用流的和。
建图:源点-工厂-商家-汇点,
源点与工厂直接费用0,流量为库存,工厂与商家直接费用用运费,流量为无穷,商家与汇点费用0,流量就是需求,然后枚举所以物品种类 k k k次,跑 k k k次费用流即可。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
#include<stdio.h>
using namespace std;

int need[1000][1000],store[1000][1000];
typedef long long int ll;
const ll inf = 0x3f3f3f3f;
const int maxn = 1e4 + 10;
struct edge{
    int v,next,w,f;
}e[maxn];
int head[maxn],tot;
void add(int u,int v,int w,int f){
    e[++tot].v = v;
    e[tot].w = w;
    e[tot].f = f;
    e[tot].next = head[u];
    head[u] = tot;
}
bool vis[maxn];
int dis[maxn];
int pre[maxn];
int flow[maxn];
bool spfa(int s,int t){
    queue<int>st;
    st.push(s);	
    memset(flow,0,sizeof(flow));
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
    vis[s] = 1;dis[s] = 0;flow[s] = inf;
    while(!st.empty()){
        int u = st.front();st.pop();
        vis[u] = 0;
        for(int i = head[u]; i ; i = e[i].next){
            int v = e[i].v;
            if(e[i].f && dis[v] > dis[u] + e[i].w){
                dis[v] = dis[u] + e[i].w;
                pre[v] = i;
                flow[v] = min(flow[u],e[i].f);
                if(!vis[v]){
                    vis[v] = true;
                    st.push(v);
                }
            }
        }
    }
    return dis[t] != 0x3f3f3f3f;
}
pair<int,int> maxflow(int s,int t){
    int ans = 0;
    int res = 0;
    while(spfa(s,t)){
        ans += dis[t] * flow[t];
        res += flow[t];
        int p = t;
        while(p != s){
            e[pre[p]].f -= flow[t];
            e[pre[p] ^ 1].f += flow[t];
            p = e[pre[p] ^ 1].v;
        }
    }
    return make_pair(ans,res);
}
int check[maxn],again[maxn];
int main(){
    int n,m,k;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF && (n || m || k)){
        memset(check,0,sizeof(check));
        memset(again,0,sizeof(again));
        for(int i = 1; i <= n; i++){//第i行表示第i个商家对第j个商品的需求量
            for(int j = 1; j <= k; j++){
                scanf("%d",&need[i][j]);
                check[j] += need[i][j];
            }
        }
        for(int i = 1; i <= m; i++){//第i个供应商对第j个商品的库存
            for(int j = 1; j <= k; j++){
                scanf("%d",&store[i][j]);
                again[j] += store[i][j];
            }
        }
        bool flag = true;
        for(int i = 1; i <= k; i++){
            if(check[i] > again[i]){
                flag = false;break;
            }
        }
        int ans = 0;
        for(int i = 1; i <= k; i++){//第j个商家到第k个供货商买第i种商品的cost
            tot = 1;
            memset(head,0,sizeof(head));
            for(int j = 1; j <= n; j++){
                for(int k = 1; k <= m; k++){
                    int x;
                    scanf("%d",&x);
                    add(k,m + j,x,inf);
                    add(m + j,k,-x,0);  
                }
            }
            int s = 0;
            int t = n + m + 1;
            for(int k = 1; k <= n; k++){ 
                add(m + k,t,0,need[k][i]);
                add(t,m + k,0,0);
            }
            for(int k = 1; k <= m; k++){
                add(s,k,0,store[k][i]);
                add(k,s,0,0);
            }
            pair<int,int> d = maxflow(s,t);
            if(d.second < check[i] || !flag){
                flag = false;continue;
            }
            ans += d.first;
        }
        if(!flag)puts("-1");
        else printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值