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

题目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;
}
原文地址:https://www.cnblogs.com/sxprovence/p/5316719.html