线性规划与网络流24题

拈花ヽ惹草 提交于 2019-12-27 03:32:02

诈个尸。

 

1.飞行员配对方案问题

二分图匹配。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 const int INF = 1e9;
  8 const int maxn = 2e5 + 10;
  9 int lv[maxn], it[maxn];
 10 int cnt, h[maxn];
 11 
 12 struct edge
 13 {
 14     int to, pre, cap;
 15 } e[maxn<<1];
 16 
 17 void init()
 18 {
 19     memset(h, -1, sizeof(h));
 20     cnt = 0;
 21 }
 22 
 23 void add(int from, int to, int cap)
 24 {
 25     e[cnt].pre = h[from];
 26     e[cnt].to = to;
 27     e[cnt].cap = cap;
 28     h[from] = cnt;
 29     cnt++;
 30 }
 31 
 32 void ad(int from, int to, int cap)
 33 {
 34     add(from, to, cap);
 35     add(to, from, 0);
 36 }
 37 
 38 void bfs(int s)
 39 {
 40     memset(lv, -1, sizeof(lv));
 41     queue<int> q;
 42     lv[s] = 0;
 43     q.push(s);
 44     while(!q.empty())
 45     {
 46         int v = q.front(); q.pop();
 47         for(int i = h[v]; i >= 0; i = e[i].pre)
 48         {
 49             int cap = e[i].cap, to = e[i].to;
 50             if(cap > 0 && lv[to] < 0)
 51             {
 52                 lv[to] = lv[v] + 1;
 53                 q.push(to);
 54             }
 55         }
 56     }
 57 }
 58 
 59 int dfs(int v, int t, int f)
 60 {
 61     if(v == t) return f;
 62     for(int &i = it[v]; i >= 0; i = e[i].pre)
 63     {
 64         int &cap = e[i].cap, to = e[i].to;
 65         if(cap > 0 && lv[v] < lv[to])
 66         {
 67             int d = dfs(to, t, min(f, cap));
 68             if(d > 0)
 69             {
 70                 cap -= d;
 71                 e[i^1].cap += d;
 72                 return d;
 73             }
 74         }
 75     }
 76     return 0;
 77 }
 78 
 79 int Dinic(int s, int t)
 80 {
 81     int flow = 0;
 82     while(1)
 83     {
 84         bfs(s);
 85         if(lv[t] < 0) return flow;
 86         memcpy(it, h, sizeof(it));
 87         int f;
 88         while((f = dfs(s, t, INF)) > 0) flow += f;
 89     }
 90 }
 91 
 92 int main(void)
 93 {
 94     init();
 95     int m, n;
 96     scanf("%d %d", &m, &n);
 97     while(1)
 98     {
 99         int u, v;
100         scanf("%d %d", &u, &v);
101         if(u == -1) break;
102         ad(u, v, 1);
103     }
104     int S = n + 1, T = S + 1;
105     for(int i = 1; i <= m; i++) ad(S, i, 1);
106     for(int i = m + 1; i <= n; i++) ad(i, T, 1);
107     int ans = Dinic(S, T);
108     if(!ans) puts("No Solution!");
109     else
110     {
111         printf("%d\n", ans);
112         for(int i = 1; i <= m; i++)
113             for(int j = h[i]; j != -1; j = e[j].pre)
114                 if(e[j].to <= n && !e[j].cap) printf("%d %d\n", i, e[j].to);
115     }
116     return 0;
117 }
Aguin

 

2.太空飞行计划问题

最大权闭合图转最大流。

见《最小割模型在信息学竞赛中的应用》。

同时注意割边必满流,满流不一定是割边。

但是Dinic找割点是很方便的,看lv就好。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <vector>
  7 using namespace std;
  8 const int INF = 1e9;
  9 const int maxn = 2e5 + 10;
 10 int lv[maxn], it[maxn];
 11 int cnt, h[maxn];
 12 vector<int> E, I;
 13 
 14 struct edge
 15 {
 16     int to, pre, cap;
 17 } e[maxn<<1];
 18 
 19 void init()
 20 {
 21     memset(h, -1, sizeof(h));
 22     cnt = 0;
 23 }
 24 
 25 void add(int from, int to, int cap)
 26 {
 27     e[cnt].pre = h[from];
 28     e[cnt].to = to;
 29     e[cnt].cap = cap;
 30     h[from] = cnt;
 31     cnt++;
 32 }
 33 
 34 void ad(int from, int to, int cap)
 35 {
 36     add(from, to, cap);
 37     add(to, from, 0);
 38 }
 39 
 40 void bfs(int s)
 41 {
 42     memset(lv, -1, sizeof(lv));
 43     queue<int> q;
 44     lv[s] = 0;
 45     q.push(s);
 46     while(!q.empty())
 47     {
 48         int v = q.front(); q.pop();
 49         for(int i = h[v]; i >= 0; i = e[i].pre)
 50         {
 51             int cap = e[i].cap, to = e[i].to;
 52             if(cap > 0 && lv[to] < 0)
 53             {
 54                 lv[to] = lv[v] + 1;
 55                 q.push(to);
 56             }
 57         }
 58     }
 59 }
 60 
 61 int dfs(int v, int t, int f)
 62 {
 63     if(v == t) return f;
 64     for(int &i = it[v]; i >= 0; i = e[i].pre)
 65     {
 66         int &cap = e[i].cap, to = e[i].to;
 67         if(cap > 0 && lv[v] < lv[to])
 68         {
 69             int d = dfs(to, t, min(f, cap));
 70             if(d > 0)
 71             {
 72                 cap -= d;
 73                 e[i^1].cap += d;
 74                 return d;
 75             }
 76         }
 77     }
 78     return 0;
 79 }
 80 
 81 int Dinic(int s, int t)
 82 {
 83     int flow = 0;
 84     while(1)
 85     {
 86         bfs(s);
 87         if(lv[t] < 0) return flow;
 88         memcpy(it, h, sizeof(it));
 89         int f;
 90         while((f = dfs(s, t, INF)) > 0) flow += f;
 91     }
 92 }
 93 
 94 int main(void)
 95 {
 96     init();
 97     int m, n, tot = 0;
 98     scanf("%d %d", &m, &n);
 99     int S = m + n + 1, T = S + 1;
100     for(int i = 1; i <= m; i++)
101     {
102         int p, x;
103         scanf("%d", &p);
104         tot += p;
105         ad(S, i, p);
106         while(getchar() == ' ')
107         {
108             scanf("%d", &x);
109             ad(i, x + m, INF);
110         }
111     }
112     for(int i = 1; i <= n; i++)
113     {
114         int c;
115         scanf("%d", &c);
116         ad(i + m, T, c);
117     }
118     int ans = tot - Dinic(S, T);
119     for(int i = 1; i <= m; i++) if(lv[i] != -1) printf("%d ", i); puts("");
120     for(int i = 1; i <= n; i++) if(lv[i+m] != -1) printf("%d ", i); puts("");
121     printf("%d\n", ans);
122     return 0;
123 }
Aguin

 

3.最小路径覆盖问题

DAG上最小路径覆盖转二分图匹配。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 const int INF = 1e9;
  8 const int maxn = 2e5 + 10;
  9 int lv[maxn], it[maxn];
 10 int cnt, h[maxn];
 11 int n, m;
 12 
 13 struct edge
 14 {
 15     int to, pre, cap;
 16 } e[maxn<<1];
 17 
 18 void init()
 19 {
 20     memset(h, -1, sizeof(h));
 21     cnt = 0;
 22 }
 23 
 24 void add(int from, int to, int cap)
 25 {
 26     e[cnt].pre = h[from];
 27     e[cnt].to = to;
 28     e[cnt].cap = cap;
 29     h[from] = cnt;
 30     cnt++;
 31 }
 32 
 33 void ad(int from, int to, int cap)
 34 {
 35     add(from, to, cap);
 36     add(to, from, 0);
 37 }
 38 
 39 void bfs(int s)
 40 {
 41     memset(lv, -1, sizeof(lv));
 42     queue<int> q;
 43     lv[s] = 0;
 44     q.push(s);
 45     while(!q.empty())
 46     {
 47         int v = q.front(); q.pop();
 48         for(int i = h[v]; i >= 0; i = e[i].pre)
 49         {
 50             int cap = e[i].cap, to = e[i].to;
 51             if(cap > 0 && lv[to] < 0)
 52             {
 53                 lv[to] = lv[v] + 1;
 54                 q.push(to);
 55             }
 56         }
 57     }
 58 }
 59 
 60 int dfs(int v, int t, int f)
 61 {
 62     if(v == t) return f;
 63     for(int &i = it[v]; i >= 0; i = e[i].pre)
 64     {
 65         int &cap = e[i].cap, to = e[i].to;
 66         if(cap > 0 && lv[v] < lv[to])
 67         {
 68             int d = dfs(to, t, min(f, cap));
 69             if(d > 0)
 70             {
 71                 cap -= d;
 72                 e[i^1].cap += d;
 73                 return d;
 74             }
 75         }
 76     }
 77     return 0;
 78 }
 79 
 80 int Dinic(int s, int t)
 81 {
 82     int flow = 0;
 83     while(1)
 84     {
 85         bfs(s);
 86         if(lv[t] < 0) return flow;
 87         memcpy(it, h, sizeof(it));
 88         int f;
 89         while((f = dfs(s, t, INF)) > 0) flow += f;
 90     }
 91 }
 92 
 93 void ans_print(int x)
 94 {
 95     printf("%d ", x);
 96     for(int i = h[x]; i >= 0; i = e[i].pre)
 97         if(!e[i].cap && e[i].to <= n + n)
 98             ans_print(e[i].to - n);
 99 }
100 
101 int main(void)
102 {
103     init();
104     scanf("%d %d", &n, &m);
105     int S = n + n + 1, T = S + 1;
106     for(int i = 1; i <= n; i++) ad(S, i, 1), ad(n + i, T, 1);
107     for(int i = 0; i < m; i++)
108     {
109         int u, v;
110         scanf("%d %d", &u, &v);
111         ad(u, v + n, 1);
112     }
113     int ans = n - Dinic(S, T);
114     for(int i = h[T]; i >= 0; i = e[i].pre)
115     {
116         if(e[i].cap) continue;
117         ans_print(e[i].to - n), puts("");
118     }
119     printf("%d\n", ans);
120     return 0;
121 }
Aguin

 

4.魔术球问题

转最小路径覆盖问题。(然而上界不是很好估计,大概不是很大。

如果二分,每次要重建图,所以不如枚举快。

枚举每次加边继续Dinic就可以了。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <vector>
  7 using namespace std;
  8 const int INF = 1e9;
  9 const int maxn = 2e4 + 10;
 10 const int maxm = 2e5;
 11 const int m = 1e4;
 12 int lv[maxn], it[maxn];
 13 int cnt, h[maxn];
 14 vector<int> is;
 15 
 16 struct edge
 17 {
 18     int to, pre, cap;
 19 } e[maxm<<1];
 20 
 21 void init()
 22 {
 23     memset(h, -1, sizeof(h));
 24     cnt = 0;
 25 }
 26 
 27 void add(int from, int to, int cap)
 28 {
 29     e[cnt].pre = h[from];
 30     e[cnt].to = to;
 31     e[cnt].cap = cap;
 32     h[from] = cnt;
 33     cnt++;
 34 }
 35 
 36 void ad(int from, int to, int cap)
 37 {
 38     add(from, to, cap);
 39     add(to, from, 0);
 40 }
 41 
 42 void bfs(int s)
 43 {
 44     memset(lv, -1, sizeof(lv));
 45     queue<int> q;
 46     lv[s] = 0;
 47     q.push(s);
 48     while(!q.empty())
 49     {
 50         int v = q.front(); q.pop();
 51         for(int i = h[v]; i >= 0; i = e[i].pre)
 52         {
 53             int cap = e[i].cap, to = e[i].to;
 54             if(cap > 0 && lv[to] < 0)
 55             {
 56                 lv[to] = lv[v] + 1;
 57                 q.push(to);
 58             }
 59         }
 60     }
 61 }
 62 
 63 int dfs(int v, int t, int f)
 64 {
 65     if(v == t) return f;
 66     for(int &i = it[v]; i >= 0; i = e[i].pre)
 67     {
 68         int &cap = e[i].cap, to = e[i].to;
 69         if(cap > 0 && lv[v] < lv[to])
 70         {
 71             int d = dfs(to, t, min(f, cap));
 72             if(d > 0)
 73             {
 74                 cap -= d;
 75                 e[i^1].cap += d;
 76                 return d;
 77             }
 78         }
 79     }
 80     return 0;
 81 }
 82 
 83 int Dinic(int s, int t)
 84 {
 85     int flow = 0;
 86     while(1)
 87     {
 88         bfs(s);
 89         if(lv[t] < 0) return flow;
 90         memcpy(it, h, sizeof(it));
 91         int f;
 92         while((f = dfs(s, t, INF)) > 0) flow += f;
 93     }
 94 }
 95 
 96 void ans_print(int x)
 97 {
 98     printf("%d ", x);
 99     for(int i = h[x]; i >= 0; i = e[i].pre)
100         if(!e[i].cap && e[i].to <= m + m)
101             ans_print(e[i].to - m);
102 }
103 
104 int main(void)
105 {
106     for(int i = 1; i * i < maxn; i++) is.push_back(i * i);
107     init();
108     int n, ans = 0;
109     scanf("%d", &n);
110     int S = m + m + 1, T = S + 1;
111     for(int i = 1; ; i++)
112     {
113         ad(S, i, 1), ad(i + m, T, 1);
114         for(int j = 0; is[j] < i + i; j++)
115             if(is[j] > i) ad(is[j] - i, i + m, 1);
116         ans += Dinic(S, T);
117         if(i - ans > n) {ans = i - 1; break;}
118     }
119     init();
120     for(int i = 1; i <= ans; i++)
121     {
122         ad(S, i, 1), ad(i + m, T, 1);
123         for(int j = 0; is[j] < i + i; j++)
124             if(is[j] > i) ad(is[j] - i, i + m, 1);
125     }
126     Dinic(S, T);
127     printf("%d\n", ans);
128     for(int i = h[T]; i >= 0; i = e[i].pre)
129     {
130         if(e[i].cap) continue;
131         ans_print(e[i].to - m), puts("");
132     }
133     return 0;
134 }
Aguin

 

5.圆桌问题

二分图匹配。多case哇。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 const int INF = 1e9;
  8 const int maxn = 2e5 + 10;
  9 int lv[maxn], it[maxn];
 10 int cnt, h[maxn];
 11 
 12 struct edge
 13 {
 14     int to, pre, cap;
 15 } e[maxn<<1];
 16 
 17 void init()
 18 {
 19     memset(h, -1, sizeof(h));
 20     cnt = 0;
 21 }
 22 
 23 void add(int from, int to, int cap)
 24 {
 25     e[cnt].pre = h[from];
 26     e[cnt].to = to;
 27     e[cnt].cap = cap;
 28     h[from] = cnt;
 29     cnt++;
 30 }
 31 
 32 void ad(int from, int to, int cap)
 33 {
 34     add(from, to, cap);
 35     add(to, from, 0);
 36 }
 37 
 38 void bfs(int s)
 39 {
 40     memset(lv, -1, sizeof(lv));
 41     queue<int> q;
 42     lv[s] = 0;
 43     q.push(s);
 44     while(!q.empty())
 45     {
 46         int v = q.front(); q.pop();
 47         for(int i = h[v]; i >= 0; i = e[i].pre)
 48         {
 49             int cap = e[i].cap, to = e[i].to;
 50             if(cap > 0 && lv[to] < 0)
 51             {
 52                 lv[to] = lv[v] + 1;
 53                 q.push(to);
 54             }
 55         }
 56     }
 57 }
 58 
 59 int dfs(int v, int t, int f)
 60 {
 61     if(v == t) return f;
 62     for(int &i = it[v]; i >= 0; i = e[i].pre)
 63     {
 64         int &cap = e[i].cap, to = e[i].to;
 65         if(cap > 0 && lv[v] < lv[to])
 66         {
 67             int d = dfs(to, t, min(f, cap));
 68             if(d > 0)
 69             {
 70                 cap -= d;
 71                 e[i^1].cap += d;
 72                 return d;
 73             }
 74         }
 75     }
 76     return 0;
 77 }
 78 
 79 int Dinic(int s, int t)
 80 {
 81     int flow = 0;
 82     while(1)
 83     {
 84         bfs(s);
 85         if(lv[t] < 0) return flow;
 86         memcpy(it, h, sizeof(it));
 87         int f;
 88         while((f = dfs(s, t, INF)) > 0) flow += f;
 89     }
 90 }
 91 
 92 int main(void)
 93 {
 94     int N, M;
 95     scanf("%d %d", &N, &M);
 96     init();
 97     int sum = 0;
 98     int S = N + M + 1, T = S + 1;
 99     for(int i = 1; i <= N; i++)
100     {
101         int cap;
102         scanf("%d", &cap);
103         sum += cap;
104         ad(S, i, cap);
105     }
106     for(int i = 1; i <= M; i++)
107     {
108         int cap;
109         scanf("%d", &cap);
110         ad(i + N, T, cap);
111     }
112     for(int i = 1; i <= N; i++)
113         for(int j = 1; j <= M; j++)
114             ad(i, j + N, 1);
115     if(Dinic(S, T) == sum)
116     {
117         puts("1");
118         for(int i = 1; i <= N; i++)
119         {
120             int fst = 1;
121             for(int j = h[i]; j >= 0; j = e[j].pre)
122             {
123                 if(e[j].to != S && e[j].cap == 0)
124                 {
125                     if(fst) printf("%d", e[j].to - N);
126                     else printf(" %d", e[j].to - N);
127                     fst = 0;
128                 }
129             }
130             puts("");
131         }
132     }
133     else puts("0");
134     return 0;
135 }
Aguin

 

6.最长递增子序列问题

第一问随便搞。后面拆点限流跑跑。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 const int INF = 1e9;
  8 const int maxn = 2e5 + 10;
  9 int lv[maxn], it[maxn];
 10 int cnt, h[maxn];
 11 
 12 struct edge
 13 {
 14     int to, pre, cap;
 15 } e[maxn<<1];
 16 
 17 void init()
 18 {
 19     memset(h, -1, sizeof(h));
 20     cnt = 0;
 21 }
 22 
 23 void add(int from, int to, int cap)
 24 {
 25     e[cnt].pre = h[from];
 26     e[cnt].to = to;
 27     e[cnt].cap = cap;
 28     h[from] = cnt;
 29     cnt++;
 30 }
 31 
 32 void ad(int from, int to, int cap)
 33 {
 34     add(from, to, cap);
 35     add(to, from, 0);
 36 }
 37 
 38 void bfs(int s)
 39 {
 40     memset(lv, -1, sizeof(lv));
 41     queue<int> q;
 42     lv[s] = 0;
 43     q.push(s);
 44     while(!q.empty())
 45     {
 46         int v = q.front(); q.pop();
 47         for(int i = h[v]; i >= 0; i = e[i].pre)
 48         {
 49             int cap = e[i].cap, to = e[i].to;
 50             if(cap > 0 && lv[to] < 0)
 51             {
 52                 lv[to] = lv[v] + 1;
 53                 q.push(to);
 54             }
 55         }
 56     }
 57 }
 58 
 59 int dfs(int v, int t, int f)
 60 {
 61     if(v == t) return f;
 62     for(int &i = it[v]; i >= 0; i = e[i].pre)
 63     {
 64         int &cap = e[i].cap, to = e[i].to;
 65         if(cap > 0 && lv[v] < lv[to])
 66         {
 67             int d = dfs(to, t, min(f, cap));
 68             if(d > 0)
 69             {
 70                 cap -= d;
 71                 e[i^1].cap += d;
 72                 return d;
 73             }
 74         }
 75     }
 76     return 0;
 77 }
 78 
 79 int Dinic(int s, int t)
 80 {
 81     int flow = 0;
 82     while(1)
 83     {
 84         bfs(s);
 85         if(lv[t] < 0) return flow;
 86         memcpy(it, h, sizeof(it));
 87         int f;
 88         while((f = dfs(s, t, INF)) > 0) flow += f;
 89     }
 90 }
 91 
 92 int a[444], dp[444];
 93 int main(void)
 94 {
 95     int n, s = 0;
 96     scanf("%d", &n);
 97     int S = 2 * n + 1, T = S + 1;
 98     for(int i = 1; i <= n; i++)
 99     {
100         scanf("%d", a + i);
101         dp[i] = 1;
102         for(int j = 1; j < i; j++)
103             if(a[i] > a[j]) dp[i] = max(dp[i], dp[j] + 1);
104         s = max(s, dp[i]);
105     }
106 
107     printf("%d\n", s);
108 
109     init();
110     for(int i = 1; i <= n; i++)
111     {
112         ad(i, i + n, 1);
113 
114         if(dp[i] == 1) ad(S, i, 1);
115         if(dp[i] == s) ad(i + n, T, 1);
116 
117         for(int j = 1; j <= i; j++)
118             if(a[j] < a[i] && dp[j] + 1 == dp[i]) ad(j + n, i, 1);
119     }
120 
121     int ans = Dinic(S, T);
122     printf("%d\n", ans);
123 
124     ad(1, 1 + n, INF);
125     ad(n, n + n, INF);
126     ad(S, 1, INF);
127     if(dp[n] == s) ad(n + n, T, INF);
128 
129     printf("%d\n", ans + Dinic(S, T));
130 
131     return 0;
132 }
Aguin

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!