POJ-1149 PIGS---最大流+建图
题目链接:
https://vjudge.net/problem/POJ-1149
题目大意:
M个猪圈,N个顾客,每个顾客有一些的猪圈的钥匙,只能购买这些有钥匙的猪圈里的猪,而且要买一定数量的猪,每个猪圈有已知数量的猪,
但是猪圈可以重新打开,将猪的个数,重新分配,以达到卖出的猪的数量最多。
思路:
难点在于如何构造容量网络
(1)将顾客看做出源点和汇点之外的结点,另外增加源点s和汇点t
(2)源点和每个猪圈的第一个用户连边,边权是猪圈中猪的数目
(3)若有重边,将权合并
(4)顾客j紧跟在顾客i之后打开某个猪圈,则边<i, j>是正无穷,因为如果顾客j紧跟在i之后,那么流到i的猪可以自由分配该j,所以设置为INF。
(5)每个顾客可汇点之间的连边,边权就是自己希望,买到的猪的数目
构建好容量网络之后,就用模板就OK啦
1 #include<iostream> 2 #include<vector> 3 #include<cstring> 4 #include<cstdio> 5 #include<queue> 6 using namespace std; 7 const int INF = 0x3f3f3f3f; 8 const int maxn = 100 + 10;//顾客的数目 9 const int maxm = 1000 + 10;//猪圈的数目 10 11 struct edge 12 { 13 int u, v, c, f; 14 edge(int u, int v, int c, int f):u(u), v(v), c(c), f(f){} 15 }; 16 vector<edge>e; 17 vector<int>G[maxn]; 18 int a[maxn], p[maxn]; 19 int m; 20 void init(int n) 21 { 22 for(int i = 0; i <= n; i++) 23 G[i].clear(); 24 e.clear(); 25 } 26 void addedge(int u, int v, int c) 27 { 28 e.push_back(edge(u, v, c, 0)); 29 e.push_back(edge(v, u, 0, 0));//反向边 30 m = e.size(); 31 G[u].push_back(m - 2); 32 G[v].push_back(m - 1); 33 } 34 int Maxflow(int s, int t) 35 { 36 int flow = 0; 37 for(;;) 38 { 39 memset(a, 0, sizeof(a));//每次找增广路的每个点的流量 40 queue<int>q; 41 q.push(s); 42 a[s] = INF; 43 while(!q.empty()) 44 { 45 int u = q.front(); 46 q.pop(); 47 for(int i = 0; i < G[u].size(); i++) 48 { 49 edge& now = e[G[u][i]]; 50 int v = now.v; 51 if(!a[v] && now.c > now.f)//v点还没有流到并且这条边还没满 52 { 53 p[v] = G[u][i];//反向记录边 54 a[v] = min(a[u], now.c - now.f);//到达v点的水量取决于边剩余的容量和u点的水量 55 q.push(v); 56 } 57 } 58 if(a[t])break;//已到达终点 59 } 60 if(!a[t])break;//已经找不到增广路 61 for(int u = t; u != s; u = e[p[u]].u) 62 { 63 e[p[u]].f += a[t]; 64 e[p[u]^1].f -= a[t]; 65 } 66 flow += a[t]; 67 } 68 return flow; 69 } 70 int pig[maxm];//每个猪圈猪的数目 71 int last[maxm];//每个猪圈的前一个顾客的序号 72 int Map[maxn][maxn];//顾客顾客之间的边,有重边,先用数组记录 73 int main() 74 { 75 int n, m; 76 cin >> m >> n; 77 for(int i = 1; i <= m; i++)cin >> pig[i]; 78 int s = 0, t = n + 1;//设置源点和汇点 79 int d, x; 80 for(int i = 1; i <= n; i++)//顾客编号 81 { 82 cin >> d; 83 for(int j = 0; j < d; j++) 84 { 85 cin >> x;//猪圈编号 86 if(last[x] == 0)//猪圈的第一个顾客 87 addedge(s, i, pig[x]); 88 else addedge(last[x], i, INF);//顾客i紧接着顾客last[x]后面打开猪圈x 89 last[x] = i; 90 } 91 cin >> x;//到汇点的边的权值 92 addedge(i, t, x); 93 } 94 cout<<Maxflow(s, t)<<endl; 95 return 0; 96 }
越努力,越幸运