线性规划与单纯型法/最小(大)费用最大流题目泛做
题目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\n", (int) (ans + 0.5)); 74 return 0; 75 }
题目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\n", (int) (ans + 0.5)); 77 return 0; 78 }
题目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\n", (int) (ans + 0.5)); 82 83 #ifndef stone 84 85 fclose(stdin); fclose(stdout); 86 87 #endif 88 89 return 0; 90 }
题目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.\n", (int)ceil(ans)); 80 81 #ifndef stone 82 83 fclose(stdin); fclose(stdout); 84 85 #endif 86 87 return 0; 88 }
仔细琢磨这两张图片,弄明白这个,你就会做裸题了。(上面的四个题)
===================================================================================================
题目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\n", ans); 92 return 0; 93 }
题目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\n", 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\n", 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; }