poj_3281Dining(网络流+拆点)

标签: 网络流


题目链接

题意:

  1. 一头牛只吃特定的几种食物和特定的几种饮料,John手里每种食物和饮料都只有一个,问最多能够满足几头牛的需求(水和食物都必须和他们的胃口)。

题解:

  1. 网络流
  2. 建图:从源点向每个食物连一条边,容量为1
  3. 将牛拆成两个点牛,牛',中间连边,容量为1
  4. 从食物向牛连边,容量为1
  5. 连牛'和饮料,容量为1
  6. 连饮料和汇点,容量为1

网络流三种算法的理解和代码实现以及相应的模板

先介绍一个定理:

  1. 最大流最小割定理:
  2. 割:去掉某几条边使得源点和汇点不再联通,那么这几条边就叫一个割,这几条边的边权和最小的就叫做最小割。
  3. 一个图的最大流就是这个图对应的最小割,可以看做是一个沙漏,最大流是要求这个沙漏每个时刻最大的流量,那就相当于是求沙漏最细的地方的流量。而最小割就相当于是用一个刀子将这个沙漏一分为二,然后找横截切面最小的就是这个沙漏最细的地方。

再介绍一些网络流的一些基本性质

  1. 流网络G的流(flow)是一个实值函数 f V ×V R,且满足下列三个性质

(1) 容量限制:对于∀u,v∈V ,要求 f (u,v) ≤ c(u,v)。

(2) 反对称性:对于∀u,v∈V ,要求 f (u,v) = −f (v,u)。

(3) 流守恒性:对于∀u,v∈V −{s,t},要求∑f (u,v) =0。

f(u,v)即为u到v的流。流 f =∑f(S,v);

最大流顾名思义就是使流f最大,也就是水龙头里能放出的水要最多。

  • EdmondsKarp算法
  1. 算法思路:

    通过多次bfs每次bfs找到一条增广路,然后更新残留网络,来寻找最大流。
  2. 算法复杂度:这个是实现起来最慢的一个,对于这个题用时 79MS
  3. 算法模板:
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<vector>
  5. #include<queue>
  6. using namespace std;
  7. const int maxn = 1008;
  8. const int INF = 111111111;
  9. struct Edge{
  10. int from,to,cap,flow;
  11. Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
  12. };
  13. int s,t;//源点。汇点
  14. struct EdmondsKarp{
  15. int n,m;
  16. vector<Edge>edge; //边数的两倍
  17. vector<int>G[maxn]; //邻接表,G[i][j]表示i的第j条边在e数组中的序号
  18. int a[maxn]; //当起点到i的可改进量
  19. int p[maxn]; //最短路树上p的入弧编号
  20. void init(int n){
  21. for(int i=0;i<=n;i++) G[i].clear();
  22. edge.clear();
  23. }
  24. void AddEdge(int from,int to,int cap){
  25. edge.push_back(Edge(from,to,cap,0));
  26. edge.push_back(Edge(to,from,0,0)); //反向弧
  27. m=edge.size();
  28. G[from].push_back(m-2);
  29. G[to].push_back(m-1);
  30. }
  31. int Maxflow(int s,int t){
  32. int flow=0;
  33. for(;;){
  34. memset(a,0,sizeof(a));
  35. queue<int>q;
  36. while(!q.empty()) q.pop();
  37. q.push(s);
  38. a[s]=INF;
  39. while(!q.empty()){
  40. int x=q.front();q.pop();
  41. for(int i=0;i<G[x].size();i++){
  42. Edge& e=edge[G[x][i]];
  43. if(!a[e.to]&&e.cap>e.flow){
  44. p[e.to]=G[x][i];
  45. a[e.to]=min(a[x],e.cap-e.flow);
  46. q.push(e.to);
  47. }
  48. }
  49. if(a[t]) break;
  50. }
  51. if(!a[t]) return flow;
  52. for(int u=t;u!=s;u=edge[p[u]].from){
  53. edge[p[u]].flow+=a[t];
  54. edge[p[u]^1].flow-=a[t];
  55. }
  56. flow+=a[t];
  57. }
  58. }
  59. };
  1. 这个题的代码:
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<vector>
  5. #include<queue>
  6. using namespace std;
  7. const int maxn = 1008;
  8. const int INF = 111111111;
  9. struct Edge{
  10. int from,to,cap,flow;
  11. Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
  12. };
  13. int s,t;
  14. struct EdmondsKarp{
  15. int n,m;
  16. vector<Edge>edge; //边数的两倍
  17. vector<int>G[maxn]; //邻接表,G[i][j]表示i的第j条边在e数组中的序号
  18. int a[maxn]; //当起点到i的可改进量
  19. int p[maxn]; //最短路树上p的入弧编号
  20. void init(int n){
  21. for(int i=0;i<=n;i++) G[i].clear();
  22. edge.clear();
  23. }
  24. void AddEdge(int from,int to,int cap){
  25. edge.push_back(Edge(from,to,cap,0));
  26. edge.push_back(Edge(to,from,0,0)); //反向弧
  27. m=edge.size();
  28. G[from].push_back(m-2);
  29. G[to].push_back(m-1);
  30. }
  31. int Maxflow(int s,int t){
  32. int flow=0;
  33. for(;;){
  34. memset(a,0,sizeof(a));
  35. queue<int>q;
  36. while(!q.empty()) q.pop();
  37. q.push(s);
  38. a[s]=INF;
  39. while(!q.empty()){
  40. int x=q.front();q.pop();
  41. for(int i=0;i<G[x].size();i++){
  42. Edge& e=edge[G[x][i]];
  43. if(!a[e.to]&&e.cap>e.flow){
  44. p[e.to]=G[x][i];
  45. a[e.to]=min(a[x],e.cap-e.flow);
  46. q.push(e.to);
  47. }
  48. }
  49. if(a[t]) break;
  50. }
  51. if(!a[t]) return flow;
  52. for(int u=t;u!=s;u=edge[p[u]].from){
  53. edge[p[u]].flow+=a[t];
  54. edge[p[u]^1].flow-=a[t];
  55. }
  56. flow+=a[t];
  57. }
  58. }
  59. };
  60. int main()
  61. {
  62. int N,F,D;
  63. s = 0;
  64. while(~scanf("%d%d%d",&N,&F,&D))
  65. {
  66. EdmondsKarp EK;
  67. t = N*2+F+D+1;
  68. EK.init(t+1);
  69. int f,d;
  70. for(int i = 1; i <= F; i++){//源点向各种食物连边
  71. EK.AddEdge(s,i,1);
  72. }
  73. int tm;
  74. for(int i = 1; i <= N; i++){
  75. scanf("%d%d",&f,&d);
  76. for(int j = 1; j <= f; j++){
  77. scanf("%d",&tm);
  78. EK.AddEdge(tm,F+i*2-1,1);//食物向喜欢它的牛连边
  79. }
  80. EK.AddEdge(F+i*2-1,F+i*2,1);//牛拆点
  81. for(int j = 1; j <= d; j++){
  82. scanf("%d",&tm);
  83. EK.AddEdge(F+i*2,2*N+F+tm,1);//牛向喜欢的饮料连边
  84. }
  85. }
  86. for(int i = 1; i <= D; i++){
  87. EK.AddEdge(2*N+F+i,t,1);//所有饮料向汇点连边
  88. }
  89. //puts("haha");
  90. int ans = EK.Maxflow(0,t);
  91. printf("%d\n",ans);
  92. }
  93. return 0;
  94. }
  • Dinic算法
  1. 算法思路:

    一次bfs一次dfs,每次bfs给每个点一个层数值(当前点到源点的距离),然后dfs通过层数的限制一次可以更新多条增广路,来寻找最大流。
  2. 算法复杂度:这个是实现起来稍微快一点的一个,一般可以解决大多数问题,复杂度是\(O(n^2m)\),对于这个题用时 32MS
  3. 算法模板:
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <vector>
  5. #include <queue>
  6. using namespace std;
  7. const int maxn = 500 + 5;
  8. const int INF = 100000000;
  9. struct Edge{
  10. int from, to, cap, flow;
  11. };
  12. struct Dinic{
  13. int n, m, s, t;
  14. vector<Edge> edges;
  15. vector<int> G[maxn];
  16. bool vis[maxn];
  17. int d[maxn];
  18. int cur[maxn];
  19. void init(int n)
  20. {
  21. this->n = n;
  22. for(int i=0; i<=n; ++i) G[i].clear();
  23. edges.clear();
  24. }
  25. void AddEdge(int from, int to, int cap)
  26. {
  27. edges.push_back((Edge){from, to, cap, 0});
  28. edges.push_back((Edge){to, from, 0, 0});
  29. m = edges.size();
  30. G[from].push_back(m-2);
  31. G[to].push_back(m-1);
  32. }
  33. bool BFS()
  34. {
  35. memset(vis, 0, sizeof vis );
  36. queue<int> Q;
  37. Q.push(s);
  38. vis[s] = 1;
  39. d[s] = 0;
  40. while(!Q.empty())
  41. {
  42. int x = Q.front(); Q.pop();
  43. for(int i=0; i<G[x].size(); ++i)
  44. {
  45. Edge& e = edges[G[x][i]];
  46. if(!vis[e.to] && e.cap > e.flow)
  47. {
  48. vis[e.to] = 1;
  49. d[e.to] = d[x] + 1;
  50. Q.push(e.to);
  51. }
  52. }
  53. }
  54. return vis[t];
  55. }
  56. int DFS(int x, int a)
  57. {
  58. if(x == t || a == 0) return a;
  59. int flow = 0, f;
  60. for(int& i = cur[x]; i<G[x].size(); ++i)
  61. {
  62. Edge& e = edges[G[x][i]];
  63. if(d[x] + 1 == d[e.to] && (f=DFS(e.to, min(a,e.cap-e.flow)))>0)
  64. {
  65. e.flow += f;
  66. edges[G[x][i]^1].flow -= f;
  67. flow += f;
  68. a -= f;
  69. if(a==0) break;
  70. }
  71. }
  72. return flow;
  73. }
  74. int Maxflow(int s, int t)
  75. {
  76. this->s = s; this->t =t;
  77. int flow = 0;
  78. while(BFS()){
  79. memset(cur, 0, sizeof cur );
  80. flow += DFS(s, INF);
  81. }
  82. return flow;
  83. }
  84. }DD;
  85. /*初始化源点汇点,点数
  86. DD.s =
  87. DD.t =
  88. DD.n =
  89. DD.init(DD.n);
  90. //加边操作
  91. DD.AddEdge(DD.s,i,1);
  92. //计算结果
  93. int ans = DD.Maxflow(0,DD.t);

4.这个题ac代码:

  1. //ac了的dinic模板
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <vector>
  6. #include <queue>
  7. using namespace std;
  8. const int maxn = 500 + 5;
  9. const int INF = 100000000;
  10. struct Edge{
  11. int from, to, cap, flow;
  12. };
  13. struct Dinic{
  14. int n, m, s, t;
  15. vector<Edge> edges;
  16. vector<int> G[maxn];
  17. bool vis[maxn];
  18. int d[maxn];
  19. int cur[maxn];
  20. void init(int n)
  21. {
  22. this->n = n;
  23. for(int i=0; i<=n; ++i) G[i].clear();
  24. edges.clear();
  25. }
  26. void AddEdge(int from, int to, int cap)
  27. {
  28. edges.push_back((Edge){from, to, cap, 0});
  29. edges.push_back((Edge){to, from, 0, 0});
  30. m = edges.size();
  31. G[from].push_back(m-2);
  32. G[to].push_back(m-1);
  33. }
  34. bool BFS()
  35. {
  36. memset(vis, 0, sizeof vis );
  37. queue<int> Q;
  38. Q.push(s);
  39. vis[s] = 1;
  40. d[s] = 0;
  41. while(!Q.empty())
  42. {
  43. int x = Q.front(); Q.pop();
  44. for(int i=0; i<G[x].size(); ++i)
  45. {
  46. Edge& e = edges[G[x][i]];
  47. if(!vis[e.to] && e.cap > e.flow)
  48. {
  49. vis[e.to] = 1;
  50. d[e.to] = d[x] + 1;
  51. Q.push(e.to);
  52. }
  53. }
  54. }
  55. return vis[t];
  56. }
  57. int DFS(int x, int a)
  58. {
  59. if(x == t || a == 0) return a;
  60. int flow = 0, f;
  61. for(int& i = cur[x]; i<G[x].size(); ++i)
  62. {
  63. Edge& e = edges[G[x][i]];
  64. if(d[x] + 1 == d[e.to] && (f=DFS(e.to, min(a,e.cap-e.flow)))>0)
  65. {
  66. e.flow += f;
  67. edges[G[x][i]^1].flow -= f;
  68. flow += f;
  69. a -= f;
  70. if(a==0) break;
  71. }
  72. }
  73. return flow;
  74. }
  75. int Maxflow(int s, int t)
  76. {
  77. this->s = s; this->t =t;
  78. int flow = 0;
  79. while(BFS()){
  80. memset(cur, 0, sizeof cur );
  81. flow += DFS(s, INF);
  82. }
  83. return flow;
  84. }
  85. }DD;
  86. int main()
  87. {
  88. int N,F,D;
  89. DD.s = 0;
  90. while(~scanf("%d%d%d",&N,&F,&D))
  91. {
  92. DD.t = N*2+F+D+1;
  93. DD.n = DD.t+1;
  94. DD.init(DD.n);
  95. int f,d;
  96. for(int i = 1; i <= F; i++){//源点向各种食物连边
  97. DD.AddEdge(DD.s,i,1);
  98. }
  99. int tm;
  100. for(int i = 1; i <= N; i++){
  101. scanf("%d%d",&f,&d);
  102. for(int j = 1; j <= f; j++){
  103. scanf("%d",&tm);
  104. DD.AddEdge(tm,F+i*2-1,1);//食物向喜欢它的牛连边
  105. }
  106. DD.AddEdge(F+i*2-1,F+i*2,1);//牛拆点
  107. for(int j = 1; j <= d; j++){
  108. scanf("%d",&tm);
  109. DD.AddEdge(F+i*2,2*N+F+tm,1);//牛向喜欢的饮料连边
  110. }
  111. }
  112. for(int i = 1; i <= D; i++){
  113. DD.AddEdge(2*N+F+i,DD.t,1);//所有饮料向汇点连边
  114. }
  115. //puts("haha");
  116. int ans = DD.Maxflow(0,DD.t);
  117. printf("%d\n",ans);
  118. }
  119. return 0;
  120. }

*ISAP算法

  1. 算法思路:

    只一次bfs和dfs动态更新标号值,bfs给每个点一个层数值(当前点到汇点的距离),然后dfs通过层数的限制一次可以更新多条增广路,来寻找最大流。这里注意,dfs过程中动态更新标号值,如果当前的这个点到汇点的边的残余流量值为0说明这个点不能再通过这个边到达汇点,所以要将这个点的标号标记为它链接的孩子的节点中标号最小的那个的标号值+1,具体的可以画个图来看一下。

    这个算法之所以快,是因为可以加一个gap优化,即设一个数组保存标号为i的节点个数为d[i]这样在d[i]出现在\(0<i<n\)的时候有d[i]==0则这个时候直接结束即可,说明从汇点已经不能到达源点了。已经没有增广路了
  2. 算法复杂度:这个是实现起来较快的一个,一般可以解决大多数问题,复杂度是\(O(n^2m)\),如果用优先队列存图,复杂度可以到达\(O(n^2\sqrt{m})\),对于这个题用时 0MS
  3. 算法模板:
  1. const int inf = 0x3fffffff;
  2. template <int N, int M>
  3. struct Isap
  4. {
  5. int top;
  6. int d[N], pre[N], cur[N], gap[N];
  7. struct Vertex{
  8. int head;
  9. } V[N];
  10. struct Edge{
  11. int v, next;
  12. int c, f;
  13. } E[M];
  14. void init(){
  15. memset(V, -1, sizeof(V));
  16. top = 0;
  17. }
  18. void add_edge(int u, int v, int c){
  19. E[top].v = v;
  20. E[top].c = c;
  21. E[top].f = 0;
  22. E[top].next = V[u].head;
  23. V[u].head = top++;
  24. }
  25. void add(int u,int v, int c){
  26. add_edge(u, v, c);
  27. add_edge(v, u, 0);
  28. }
  29. void set_d(int t){
  30. queue<int> Q;
  31. memset(d, -1, sizeof(d));
  32. memset(gap, 0, sizeof(gap));
  33. d[t] = 0;
  34. Q.push(t);
  35. while(!Q.empty()) {
  36. int v = Q.front(); Q.pop();
  37. ++gap[d[v]];
  38. for(int i = V[v].head; ~i; i = E[i].next) {
  39. int u = E[i].v;
  40. if(d[u] == -1) {
  41. d[u] = d[v] + 1;
  42. Q.push(u);
  43. }
  44. }
  45. }
  46. }
  47. int sap(int s, int t, int num) {
  48. set_d(t);
  49. int ans = 0, u = s;
  50. int flow = inf;
  51. memcpy(cur, V, sizeof(V));
  52. while(d[s] < num) {
  53. int &i = cur[u];
  54. for(; ~i; i = E[i].next) {
  55. int v = E[i].v;
  56. if(E[i].c > E[i].f && d[u] == d[v] + 1) {
  57. u = v;
  58. pre[v] = i;
  59. flow = min(flow, E[i].c - E[i].f);
  60. if(u == t) {
  61. while(u != s) {
  62. int j = pre[u];
  63. E[j].f += flow;
  64. E[j^1].f -= flow;
  65. u = E[j^1].v;
  66. }
  67. ans += flow;
  68. flow = inf;
  69. }
  70. break;
  71. }
  72. }
  73. if(i == -1) {
  74. if(--gap[d[u]] == 0)
  75. break;
  76. int dmin = num - 1;
  77. cur[u] = V[u].head;
  78. for(int j = V[u].head; ~j; j = E[j].next)
  79. if(E[j].c > E[j].f)
  80. dmin = min(dmin, d[E[j].v]);
  81. d[u] = dmin + 1;
  82. ++gap[d[u]];
  83. if(u != s)
  84. u = E[pre[u] ^ 1].v;
  85. }
  86. }
  87. return ans;
  88. }
  89. };
  90. Isap<1000, 1000000> Sap;
  91. 调用方式:
  92. Sap.init(); //建边前调用
  93. Sap.add(u, v, c); //在u->v之间建一条容量为c的边
  94. Sap.sap(s, t, num); //s为源点,t为汇点,num为边的数量
  1. 这个题AC代码:
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <vector>
  5. #include <queue>
  6. using namespace std;
  7. const int inf = 0x3fffffff;
  8. template <int N, int M>
  9. struct Isap
  10. {
  11. int top;
  12. int d[N], pre[N], cur[N], gap[N];
  13. struct Vertex{
  14. int head;
  15. } V[N];
  16. struct Edge{
  17. int v, next;
  18. int c, f;
  19. } E[M];
  20. void init(){
  21. memset(V, -1, sizeof(V));
  22. top = 0;
  23. }
  24. void add_edge(int u, int v, int c){
  25. E[top].v = v;
  26. E[top].c = c;
  27. E[top].f = 0;
  28. E[top].next = V[u].head;
  29. V[u].head = top++;
  30. }
  31. void add(int u,int v, int c){
  32. add_edge(u, v, c);
  33. add_edge(v, u, 0);
  34. }
  35. void set_d(int t){
  36. queue<int> Q;
  37. memset(d, -1, sizeof(d));
  38. memset(gap, 0, sizeof(gap));
  39. d[t] = 0;
  40. Q.push(t);
  41. while(!Q.empty()) {
  42. int v = Q.front(); Q.pop();
  43. ++gap[d[v]];
  44. for(int i = V[v].head; ~i; i = E[i].next) {
  45. int u = E[i].v;
  46. if(d[u] == -1) {
  47. d[u] = d[v] + 1;
  48. Q.push(u);
  49. }
  50. }
  51. }
  52. }
  53. int sap(int s, int t, int num) {
  54. set_d(t);
  55. int ans = 0, u = s;
  56. int flow = inf;
  57. memcpy(cur, V, sizeof(V));
  58. while(d[s] < num) {
  59. int &i = cur[u];
  60. for(; ~i; i = E[i].next) {
  61. int v = E[i].v;
  62. if(E[i].c > E[i].f && d[u] == d[v] + 1) {
  63. u = v;
  64. pre[v] = i;
  65. flow = min(flow, E[i].c - E[i].f);
  66. if(u == t) {
  67. while(u != s) {
  68. int j = pre[u];
  69. E[j].f += flow;
  70. E[j^1].f -= flow;
  71. u = E[j^1].v;
  72. }
  73. ans += flow;
  74. flow = inf;
  75. }
  76. break;
  77. }
  78. }
  79. if(i == -1) {
  80. if(--gap[d[u]] == 0)
  81. break;
  82. int dmin = num - 1;
  83. cur[u] = V[u].head;
  84. for(int j = V[u].head; ~j; j = E[j].next)
  85. if(E[j].c > E[j].f)
  86. dmin = min(dmin, d[E[j].v]);
  87. d[u] = dmin + 1;
  88. ++gap[d[u]];
  89. if(u != s)
  90. u = E[pre[u] ^ 1].v;
  91. }
  92. }
  93. return ans;
  94. }
  95. };
  96. Isap<1000, 1000000> Sap;
  97. int main()
  98. {
  99. int N,F,D;
  100. int s, t, num;
  101. while(~scanf("%d%d%d",&N,&F,&D))
  102. {
  103. t = N*2+F+D+1;
  104. s = 0;
  105. num = t+1;
  106. Sap.init();
  107. int f,d;
  108. for(int i = 1; i <= F; i++){//源点向各种食物连边
  109. Sap.add(s,i,1);
  110. }
  111. int tm;
  112. for(int i = 1; i <= N; i++){
  113. scanf("%d%d",&f,&d);
  114. for(int j = 1; j <= f; j++){
  115. scanf("%d",&tm);
  116. Sap.add(tm,F+i*2-1,1);//食物向喜欢它的牛连边
  117. }
  118. Sap.add(F+i*2-1,F+i*2,1);//牛拆点
  119. for(int j = 1; j <= d; j++){
  120. scanf("%d",&tm);
  121. Sap.add(F+i*2,2*N+F+tm,1);//牛向喜欢的饮料连边
  122. }
  123. }
  124. for(int i = 1; i <= D; i++){
  125. Sap.add(2*N+F+i,t,1);//所有饮料向汇点连边
  126. }
  127. //puts("haha");
  128. int ans = Sap.sap(s,t,num);
  129. printf("%d\n",ans);
  130. }
  131. return 0;
  132. }

poj_3281Dining(网络流+拆点)的更多相关文章

  1. ACM/ICPC 之 网络流-拆点构图(POJ2391)

    需要直接到达,因此源点经过三条边后必须要达到汇点,但为了保证网络流的正确性(路径可反悔),因此不可限制层次网络的最高层次为3,最好的方法既是让所有点拆分成两个点,一个点从汇点进入,一个点通向汇点,任意 ...

  2. hiho# 1394最小路径覆盖 网络流拆点

    题目传送门 思路: 观察到路径上除了终点起点以外的每个点出度和入度都为1,和网络流的拆点很像,所以就把每个点都拆成两个点,若存在一条路径$(u,v)$,则建一条$(u,v+n,1)$的边,然后求出最大 ...

  3. poj 3281 Dining(网络流+拆点)

    Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20052   Accepted: 8915 Descripti ...

  4. POJ2391 Ombrophobic Bovines 网络流拆点+二分+floyed

    题目链接: id=2391">poj2391 题意: 有n块草地,每块草地上有一定数量的奶牛和一个雨棚,并给出了每一个雨棚的容(牛)量. 有m条路径连接这些草地  ,这些路径是双向的, ...

  5. ACM Computer Factory POJ - 3436 网络流拆点+路径还原

    http://poj.org/problem?id=3436 每台电脑有$p$个组成部分,有$n$个工厂加工电脑. 每个工厂对于进入工厂的半成品的每个组成部分都有要求,由$p$个数字描述,0代表这个部 ...

  6. Food HDU - 4292 网络流 拆点建图

    http://acm.hdu.edu.cn/showproblem.php?pid=4292 给一些人想要的食物和饮料,和你拥有的数量,问最多多少人可以同时获得一份食物和一份饮料 写的时候一共用了2种 ...

  7. poj 3281(网络流+拆点)

    题目链接:http://poj.org/problem?id=3281 思路:设一个超级源点和一个超级汇点,源点与食物相连,饮料与汇点相连,然后就是对牛进行拆点,一边喜欢的食物相连,一边与喜欢的饮料相 ...

  8. POJ 3281 Dining(网络流拆点)

    [题目链接] http://poj.org/problem?id=3281 [题目大意] 给出一些食物,一些饮料,每头牛只喜欢一些种类的食物和饮料, 但是每头牛最多只能得到一种饮料和食物,问可以最多满 ...

  9. hdu 4289 网络流拆点,类似最小割(可做模板)邻接矩阵实现

    Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

随机推荐

  1. 谷歌浏览器插件-jsonView插件安装与使用

    本文转载:http://www.bubuko.com/infodetail-700647.html 1 安装 1.打开 https://github.com : 2.搜索 jsonView 链接:ht ...

  2. Python学习日记day3:数据类型

    1.数据类型int :如1.2.4等, 用于计算 bool: True , False ,用户判断 str: 储存少量数据,进行操作.如:'fdasklfjfladfl','而而噩噩','1234' ...

  3. 【NOIP模拟】从我背后出现

    Description 给定n个点m条边的无向连通图,对于每条边求出强制选这条边后的最⼩⽣成树⼤⼩. \(n\leq 10^5,m\leq 2*10^5\) Input Format 第 1 行包含两 ...

  4. 三菱Q系列PLC的智能功能模块程序

    一.模拟量输入模块Q64AD 1.模块开关或者参数设置 1.1I/O分配 1.2开关设置使用通道1,0-5v, 1.3使用GX configurator设置自动刷新PLC设置智能功能模块参数,即将模拟 ...

  5. Spring基础篇——DI和AOP初识

    前言 作为从事java开发的码农,Spring的重要性不言而喻,你可能每天都在和Spring框架打交道.Spring恰如其名的,给java应用程序的开发带了春天般的舒爽感觉.Spring,可以说是任何 ...

  6. 在win7下用net命令无法实现对用户的创建(未完成)

    ============================================================================================= 201307 ...

  7. 小白的Python之路 day4 软件目录结构规范

    软件目录结构规范 为什么要设计好目录结构? "设计项目目录结构",就和"代码编码风格"一样,属于个人风格问题.对于这种风格上的规范,一直都存在两种态度: 一类同 ...

  8. git 的回退

    今天下午写了一下午的代码给合并没了 然后晚上觉得还是要好好学习一下git的使用 推荐几个git的教程 https://www.liaoxuefeng.com/wiki/0013739516305929 ...

  9. 更好的小票打印体验,huanent.printer2.0发布

    huanent.printer2.0是一个专注消费小票打印的类库.拥有许多先进的特性例如居中打印.自动换行等特性,可以通过简洁的代码来打印出复杂的消费小票.huanent.printer通过MIT方式 ...

  10. python科学计算_numpy_广播与下标

    多维数组下标 多维数组的下标是用元组来实现每一个维度的,如果元组的长度比维度大则会出错,如果小,则默认元组后面补 : 表示全部访问: 如果一个下标不是元组,则先转换为元组,在转换过程中,列表和数组的转 ...