• 线性规划与单纯型法/最小(大)费用最大流题目泛做


    题目1 NOI2008 志愿者招募

    题解什么的后补吧,先上代码。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <algorithm>
     5 #include <iostream>
     6 #include <cmath>
     7  
     8 using namespace std;
     9  
    10 const double eps = 1e-6;
    11 const double inf = 1e10;
    12 const int N = 1000 + 5;
    13 const int M = 10000 + 5;
    14  
    15 int n, m;
    16 double c[N], A[M][N], b[M], v;
    17  
    18 void Pivot(int l, int e) {
    19   b[l] /= A[l][e];
    20   for(int i = 1; i <= n; ++ i)
    21     if(i != e) A[l][i] /= A[l][e];
    22   A[l][e] = 1 / A[l][e];
    23   for(int i = 1; i <= m; ++ i) {
    24     if(i != l && fabs(A[i][e]) > eps) {
    25       b[i] -= A[i][e] * b[l];
    26       for(int j = 1; j <= n; ++ j) {
    27         if(j != e) {
    28           A[i][j] -= A[i][e] * A[l][j];
    29         }
    30       }
    31       A[i][e] = -A[i][e] * A[l][e];
    32     }
    33   }
    34   v += c[e] * b[l];
    35   for(int i = 1; i <= n; ++ i)
    36     if(i != e)
    37       c[i] -= c[e] * A[l][i];
    38   c[e] = -c[e] * A[l][e];
    39 }
    40  
    41  
    42 double Simplex() {
    43   int i, l, e;
    44   for(;;) {
    45     for(i = 1; i <= n; ++ i)
    46       if(c[i] > eps) break;
    47     e = i;
    48     if(e == n + 1) return v;
    49     double tmp = inf;
    50     for(i = 1; i <= m; ++ i) {
    51       if(A[i][e] > eps && b[i] / A[i][e] < tmp) {
    52         tmp = b[i] / A[i][e];
    53         l = i;
    54       }
    55     }
    56     if(tmp == inf) return inf;
    57     Pivot(l, e);
    58   }
    59 }
    60  
    61 int main() {
    62   int x, y, z;
    63   scanf("%d%d", &n, &m);
    64   for(int i = 1; i <= n; ++ i)
    65     scanf("%lf", &c[i]);
    66   for(int i = 1; i <= m; ++ i) {
    67     scanf("%d%d%d", &x, &y, &z);
    68     for(int j = x; j <= y; ++ j)
    69       A[i][j] = 1;
    70     b[i] = z;
    71   }
    72   double ans = Simplex();
    73   printf("%d
    ", (int) (ans + 0.5));
    74   return 0;
    75 }
    NOI2008

    题目2 志愿者招募加强版

     1 #include <cstdlib>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 #include <iostream>
     6 #include <cmath>
     7  
     8 using namespace std;
     9 const double eps = 1e-10;
    10 const double inf = 1e10;
    11 const int N = 1000 + 5;
    12 const int M = 10000 + 5;
    13  
    14 int n, m, k;
    15 double A[M][N], c[N], b[M], v;
    16  
    17  
    18 void Pivot(int l, int e) {
    19   b[l] /= A[l][e];
    20   for(int i = 1; i <= n; ++ i)
    21     if(i != e) A[l][i] /= A[l][e];
    22   A[l][e] = 1 / A[l][e];
    23   for(int i = 1; i <= m; ++ i) {
    24     if(i != l && fabs(A[i][e]) > eps) {
    25       b[i] -= A[i][e] * b[l];
    26       for(int j = 1; j <= n; ++ j) {
    27         if(j != e) {
    28           A[i][j] -= A[i][e] * A[l][j];
    29         }
    30       }
    31       A[i][e] = -A[i][e] * A[l][e];
    32     }
    33   }
    34   v += c[e] * b[l];
    35   for(int i = 1; i <= n; ++ i)
    36     if(i != e) c[i] -= c[e] * A[l][i];
    37   c[e] = -c[e] * A[l][e];
    38 }
    39  
    40 double Simplex() {
    41   int i, l, e;
    42   while(1) {
    43     for(i = 1; i <= n; ++ i)
    44       if(c[i] > eps) break;
    45     e = i;
    46     if(e == n + 1) return v;
    47     double tmp = inf;
    48     for(i = 1; i <= m; ++ i) {
    49       if(A[i][e] > eps && b[i] / A[i][e] < tmp) {
    50         tmp = b[i] / A[i][e];
    51         l = i;
    52       }
    53     }
    54     if(tmp == inf) return inf;
    55     Pivot(l, e);
    56   }
    57 }
    58  
    59 int main() {
    60   int x, y, z;
    61   scanf("%d%d", &n, &m);
    62   for(int i = 1; i <= n; ++ i) {
    63     scanf("%lf", &c[i]);
    64   }
    65   for(int i = 1; i <= m; ++ i) {
    66     scanf("%d", &k);
    67     for(int j = 1; j <= k; ++ j) {
    68       scanf("%d%d", &x, &y);
    69       for(int g = x; g <= y; ++ g)
    70         A[i][g] = 1;
    71     }
    72     scanf("%d", &z);
    73     b[i] = z;
    74   }
    75   double ans = Simplex();
    76   printf("%d
    ", (int) (ans + 0.5));
    77   return 0;
    78 }
    3265

    题目3 ZJOI 防守战线

     1 #include <cstdlib>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7  
     8 using namespace std;
     9 const int N = 1000 + 5;
    10 const int M = 10000 + 5;
    11 const double eps = 1e-10;
    12 const double inf = 1e10;
    13  
    14 int n, m;
    15 double A[N][M], c[M], b[M], v;
    16  
    17 void Pivot(int l, int e) {
    18   b[l] /= A[l][e];
    19   for(int i = 1; i <= n; ++ i)
    20     if(i != e) A[l][i] /= A[l][e];
    21   A[l][e] = 1 / A[l][e];
    22   for(int i = 1; i <= m; ++ i) {
    23     if(i != l && fabs(A[i][e]) > eps) {
    24       b[i] -= A[i][e] * b[l];
    25       for(int j = 1; j <= n; ++ j) {
    26         if(j != e) {
    27           A[i][j] -= A[i][e] * A[l][j];
    28         }
    29       }
    30       A[i][e] = -A[i][e] * A[l][e];
    31     }
    32   }
    33   v += c[e] * b[l];
    34   for(int i = 1; i <= n; ++ i)
    35     if(i != e) c[i] -= c[e] * A[l][i];
    36   c[e] = -c[e] * A[l][e];
    37 }
    38  
    39 double Simplex() {
    40   int i, l, e;
    41   while(1) {
    42     for(i = 1; i <= n; ++ i)
    43       if(c[i] > eps) break;
    44     e = i;
    45     if(e == n + 1) return v;
    46     double tmp = inf;
    47     for(i = 1; i <= m; ++ i) {
    48       if(A[i][e] > eps && b[i] / A[i][e] < tmp) {
    49         tmp = b[i] / A[i][e];
    50         l = i;
    51       }
    52     }
    53     if(tmp == inf) return inf;
    54     Pivot(l, e);
    55   }
    56 }
    57  
    58 #define stone
    59  
    60 int main() {
    61 #ifndef stone
    62  
    63   freopen("zjoi13_defend.in", "r", stdin);
    64   freopen("zjoi13_defend.out", "w", stdout);
    65  
    66 #endif
    67    
    68   int x, y, z;
    69   scanf("%d%d", &m, &n);
    70   for(int i = 1; i <= m; ++ i) {
    71     scanf("%lf", &b[i]);
    72   }
    73   for(int i = 1; i <= n; ++ i) {
    74     scanf("%d%d%d", &x, &y, &z);
    75     for(int j = x; j <= y; ++ j) {
    76       A[j][i] = 1;
    77     }
    78     c[i] = z;
    79   }
    80   double ans = Simplex();
    81   printf("%d
    ", (int) (ans + 0.5));
    82  
    83 #ifndef stone
    84  
    85   fclose(stdin); fclose(stdout);
    86  
    87 #endif
    88  
    89   return 0;
    90 }
    ZJOI

    题目4 Uva 10498 满意值

    裸单纯型,最后要注意的就是,因为每个人要买相同的,所以要乘以m。

     1 #include <cstdlib>
     2 #include <cstdio>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <cmath>
     7 
     8 using namespace std;
     9 const double inf = 1e10;
    10 const double eps = 1e-10;
    11 const int N = 25;
    12 
    13 int n, m;
    14 double A[N][N], b[N], c[N], v;
    15 
    16 void Pivot(int l, int e) {
    17   b[l] /= A[l][e];
    18   for(int i = 1; i <= n; ++ i)
    19     if(i != e) A[l][i] /= A[l][e];
    20   A[l][e] = 1 / A[l][e];
    21   for(int i = 1; i <= m; ++ i) {
    22     if(i != l && fabs(A[i][e]) > eps) {
    23       b[i] -= b[l] * A[i][e];
    24       for(int j = 1; j <= n; ++ j) {
    25         if(j != e) {
    26           A[i][j] -= A[i][e] * A[l][j];
    27         }
    28       }
    29       A[i][e] = - A[i][e] * A[l][e];
    30     }
    31   }
    32   v += c[e] * b[l];
    33   for(int i = 1; i <= n; ++ i)
    34     if(i != e) c[i] -= c[e] * A[l][i];
    35   c[e] = -c[e] * A[l][e];
    36 }
    37 
    38 double Simplex() {
    39   int i, l, e;
    40   for(;;) {
    41     for(i = 1; i <= n; ++ i)
    42       if(c[i] > eps) break;
    43     e = i;
    44     if(e == n + 1) return v;
    45     double tmp = inf;
    46     for(i = 1; i <= m; ++ i) {
    47       if(A[i][e] > eps && b[i] / A[i][e] < tmp) {
    48         tmp = b[i] / A[i][e];
    49         l = i;
    50       }
    51     }
    52     if(tmp == inf) return inf;
    53     Pivot(l, e);
    54   }
    55 }
    56 
    57 #define stonee
    58 
    59 int main() {
    60 #ifndef stone
    61 
    62   freopen("happiness.in", "r", stdin);
    63   freopen("happiness.out", "w", stdout);
    64 
    65 #endif
    66 
    67   scanf("%d%d", &n, &m);
    68   for(int i = 1; i <= n; ++ i) {
    69     scanf("%lf", &c[i]);
    70   }
    71   for(int i = 1; i <= m; ++ i) {
    72     for(int j = 1; j <= n; ++ j) {
    73       scanf("%lf", &A[i][j]);
    74     }
    75     scanf("%lf", &b[i]);
    76   }
    77   double ans = Simplex();
    78   ans = ans * 1.0 * m;
    79   printf("Nasa can spend %d taka.
    ", (int)ceil(ans));
    80   
    81 #ifndef stone
    82 
    83   fclose(stdin); fclose(stdout);
    84 
    85 #endif
    86 
    87   return 0;
    88 }
    Uva 10498

    仔细琢磨这两张图片,弄明白这个,你就会做裸题了。(上面的四个题)

    ===================================================================================================

    题目4 BZOJ1221 HNOI 软件开发

    算法讨论: mcmf

    把每天拆成两个点,一个连向源点,流量为d[i],一个连向汇点,流量为d[i],花费都为0.

    如果今天直接买手巾,就从源点向连向汇点的那个点,连流量为无穷,花费为f的边。

    然后我们考虑每天对后面几天的影响,如果今天买然后送到a去洗,那么第a+1之后的那天不用有额外的花费,这之间产生了fa的花费

    b也是一样的考虑,所以 从每个点向a + 1天之后连fa的边,向b + 1天之后连fb的边。

    然后i向i + 1还要连边,这是考虑上一天的手巾没有用完,可以放一夜直接拿来用的原因。

    mcmf就可以。WA了一遍是因为que数组开小了。

    看样子que[N << 1]还是很有必要的。不,队列越大越好,因为东西我三个题都没有1A。然后要记住第一天送到洗的手巾,是一晚上就可以洗出来,

    还是要一晚上和一整天。意思明白?

     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <queue>
     8  
     9 using namespace std;
    10 const int N = 2000 + 10;
    11 const int inf = 0x3f3f3f3f;
    12 struct Edge {
    13   int from, to, cap, flow, cost;
    14   Edge(int u=0, int v=0, int cp=0, int fw=0, int ct=0):
    15     from(u), to(v), cap(cp), flow(fw), cost(ct) {}
    16 };
    17  
    18 int n, a, b, f, fa, fb, d[N], ans;
    19 struct MCMF {
    20   int n, m;
    21   int dis[N], pre[N], que[N << 1], a[N];
    22   bool vis[N];
    23   vector <int> G[N];
    24   vector <Edge> edges;
    25  
    26   void insert(int from, int to, int cap, int cost) {
    27     edges.push_back(Edge(from, to, cap, 0, cost));
    28     edges.push_back(Edge(to, from, 0, 0, -cost));
    29     m = edges.size();
    30     G[from].push_back(m - 2);
    31     G[to].push_back(m -1);
    32   }
    33  
    34   bool bfs(int s, int t, int &flow, int &cost) {
    35     int head = 1, tail = 1;
    36     for(int i = 0; i <= n; ++ i) dis[i] = inf;
    37     memset(vis, false, sizeof vis);
    38     dis[s] = 0; pre[s] = 0; a[s] = inf; vis[s] = true;
    39     que[head] = s;
    40     while(head <= tail) {
    41       int x = que[head];
    42       vis[x] = false;
    43       for(int i = 0; i < (signed) G[x].size(); ++ i) {
    44         Edge &e = edges[G[x][i]];
    45         if(e.cap > e.flow && dis[e.to] > dis[x] + e.cost) {
    46           dis[e.to] = dis[x] + e.cost;
    47           pre[e.to] = G[x][i];
    48           a[e.to] = min(a[x], e.cap - e.flow);
    49           if(!vis[e.to]) {
    50             vis[e.to] = true;
    51             que[++ tail] = e.to;
    52           }
    53         }
    54       }
    55       ++ head;
    56     }
    57     if(dis[t] == inf) return false;
    58     flow += a[t];
    59     cost += a[t] * dis[t];
    60     int now = t;
    61     while(now != s) {
    62       edges[pre[now]].flow += a[t];
    63       edges[pre[now] ^ 1].flow -= a[t];
    64       now = edges[pre[now]].from;
    65     }
    66     return true;
    67   }
    68   void mcmf(int s, int t, int &cost) {
    69     int flow = 0;
    70     while(bfs(s, t, flow, cost));
    71   }
    72 }net;
    73  
    74 int main() {
    75   int tp;
    76   scanf("%d%d%d%d%d%d", &n, &a, &b, &f, &fa, &fb);
    77   tp = n << 1;
    78   for(int i = 1; i <= n; ++ i) {
    79     scanf("%d", &d[i]);
    80     net.insert(0, i, d[i], 0);
    81     net.insert(i + n, tp + 1, d[i], 0);
    82   }
    83   for(int i = 1; i <= n; ++ i) {
    84     if(i + 1 <= n) net.insert(i, i + 1, inf, 0);
    85     if(i + a + 1 <= n) net.insert(i, i + n + a + 1, inf, fa);
    86     if(i + b + 1 <= n) net.insert(i, i + n + b + 1, inf, fb);
    87     net.insert(0, i + n, inf, f);
    88   }
    89   net.n = tp + 1;
    90   net.mcmf(0, tp + 1, ans);
    91   printf("%d
    ", ans);
    92   return 0;
    93 }
    1221

    题目5 SDOI2016

    算法讨论:

    最大费用最大流。用SPFA求最长路。初值设为-inf.然后自己一直炸是因为inf开得太小了。

    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    using namespace std;
    const int N = 400 + 5;
    typedef long long ll;
    const ll inf = (1LL<<60);
    
    int n, T;
    int aa[N], b[N], c[N];
    
    struct Edge {
      int from, to;
      ll cap, flow, cost;
      Edge(int u=0, int v=0, ll cap=0, ll flow=0, ll cost=0):
    	from(u), to(v), cap(cap), flow(flow), cost(cost) {}
    };
    
    struct MCMF {
      int n, mm, s, t;
      int pre[N], que[N << 3];
      ll a[N], dis[N];
      bool vis[N];
      vector <Edge> edges;
      vector <int> G[N];
    
      void add(int from, int to, ll cap, ll cost) {
    	edges.push_back(Edge(from, to, cap, 0, cost));
    	edges.push_back(Edge(to, from, 0, 0, -cost));
    	mm = edges.size();
    	G[from].push_back(mm - 2);
    	G[to].push_back(mm - 1);
      }
    
      bool bfs(ll &fw, ll &ct) {
    	int head = 1, tail = 1;
    	for(int i = 0; i <= n; ++ i) {
    	  dis[i] = -inf; vis[i] = false;
    	}
    	dis[s] = 0; que[head] = s; vis[s] = true;
    	pre[s] = 0; a[s] = inf;
    	while(head <= tail) {
    	  int x = que[head];
    	  vis[x] = false;
    	  for(int i = 0; i < (signed) G[x].size(); ++ i) {
    		Edge &e = edges[G[x][i]];
    		if(e.cap > e.flow && dis[e.to] < dis[x] + e.cost) {
    		  dis[e.to] = dis[x] + e.cost;
    		  pre[e.to] = G[x][i];
    		  a[e.to] = min(a[x], e.cap - e.flow);
    		  if(!vis[e.to]) {
    			vis[e.to] = true;
    			que[++ tail] = e.to;
    		  }
    		}
    	  }
    	  ++ head;
    	}
    	if(dis[t] == -inf) return false;
    	ll tmp = ct, tfw = fw;
    	fw += a[t];
    	ct += 1LL * a[t] * dis[t];
    	if(ct < 0) {
    	  fw = tfw;
    	  fw += tmp / (-dis[t]);
    	  printf("%lld
    ", fw / 2);
    	  exit(0);
    	}
    	int now = t;
    	while(now != s) {
    	  edges[pre[now]].flow += a[t];
    	  edges[pre[now] ^ 1].flow -= a[t];
    	  now = edges[pre[now]].from;
    	}
    	return true;
      }
    
      void mcmf(int s, int t) {
    	this->s = s; this->t = t;
    	ll fw = 0, ct = 0;
    	while(bfs(fw, ct));
    	printf("%lld
    ", fw / 2);
      }
    }net;
    
    bool check(int nv) {
      if(nv == 1) return false;
      if(nv == 2) return true;
      int m = (int) sqrt(nv + 0.5);
      for(int i = 2; i <= m; ++ i) if(nv % i == 0) return false;
      return true;
    }
    
    #define stone_ee
    int main() {
    #ifndef stone_
      freopen("menci_pair.in", "r", stdin);
      freopen("menci_pair.out", "w", stdout);
    #endif
      
      scanf("%d", &n);
      net.n = (n << 1) + 1;
      T = (n << 1) + 1;
      for(int i = 1; i <= n; ++ i) scanf("%d", &aa[i]);
      for(int i = 1; i <= n; ++ i) scanf("%d", &b[i]);
      for(int i = 1; i <= n; ++ i) scanf("%d", &c[i]);
      for(int i = 1; i <= n; ++ i) {
    	net.add(0, i, b[i], 0);
    	net.add(i + n, T, b[i], 0);
      }
      for(int i = 1; i <= n; ++ i)
    	for(int j = 1; j <= n; ++ j)
    	  if(i != j)
    		if(aa[i] % aa[j] == 0)
    		  if(check(aa[i] / aa[j])) {
    			net.add(i, j + n, inf, 1LL * c[j] * c[i]);
    			net.add(j, i + n, inf, 1LL * c[j] * c[i]);
    		  }
      net.mcmf(0, T);
    
    #ifndef stone_
      fclose(stdin); fclose(stdout);
    #endif
      return 0;
    }
    
  • 相关阅读:
    整数因子分解问题(递归分治法、动态规划)
    背包问题(动态规划 C/C++)
    划分问题(Java 动态规划)
    算法:Common Subsequence(动态规划 Java 最长子序列)
    算法:矩阵连乘(Java)动态规划
    Frogs‘ Neighborhood(POJ 1659 C/C++)
    算法:线性时间选择(C/C++)
    sort(hdu oj 1425)计数排序和快速排序
    快速排序(递归和分治)
    a^b(取模运算)
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5316719.html
Copyright © 2020-2023  润新知