2017 01 05 校内网络流小测

鉴于这几日大家都有学习网络流知识,LincHpin大爷决定考一考我们网络流,然后,我就爆零了,233……

T1 Seal

想了好久,也不知道怎么建图,然后心态就崩了,就刷BZOJ去了……

考场上写的随机化和错误贪心都被大爷卡了,T_T,Orz YYH,YZY,GZZ三位AK大佬。

首先,以一个恶魔为中心,形成一个直角的充要条件是,在左右相邻格子中选一个,在上下相邻格子中选一个。

然后发现,对于那些水晶格,同为奇数行的总是不会同时被选,同为偶数行的也不会同时被选(此指被选中流向同一个恶魔格子)。就是说,水晶格可以按照所在行(或者列,随便啦)的奇偶进行黑白染色,每个恶魔总是需要匹配一个黑水晶和一个白水晶。

所以把黑水晶放在左侧,每个和源点之间有容量为1的边;白水晶放在右侧,每个和汇点之间也有容量为1的边。中间是恶魔点,每个恶魔拆成两个点,分别和相邻的黑、白水晶相连,中间是容量为1的边。跑最大流就行了。

  1 #include <cstdio>
  2 
  3 inline int nextChar(void) {
  4     const int siz = 1024;
  5     
  6     static char buf[siz];
  7     static char *hd = buf + siz;
  8     static char *tl = buf + siz;
  9     
 10     if (hd == tl)
 11         fread(hd = buf, 1, siz, stdin);
 12         
 13     return *hd++;
 14 }
 15  
 16 inline int nextInt(void) {
 17     register int ret = 0;
 18     register int neg = false;
 19     register int bit = nextChar();
 20     
 21     for (; bit < 48; bit = nextChar())
 22         if (bit == '-')neg ^= true;
 23         
 24     for (; bit > 47; bit = nextChar())
 25         ret = ret * 10 + bit - 48;
 26         
 27     return neg ? -ret : ret;
 28 }
 29 
 30 int n, m;
 31 
 32 bool g[55][55];
 33 
 34 inline bool next(void)
 35 {
 36     char c = nextChar();
 37     
 38     while (c != '.' && c != 'X')
 39         c = nextChar();
 40         
 41     return c == '.';
 42 }
 43 
 44 const int siz = 500005;
 45 const int inf = 1000000007;
 46 
 47 int tot;
 48 int s, t;
 49 int hd[siz];
 50 int to[siz];
 51 int fl[siz];
 52 int nt[siz];
 53 
 54 inline void add(int u, int v, int f)
 55 {
 56     nt[tot] = hd[u]; to[tot] = v; fl[tot] = f; hd[u] = tot++;
 57     nt[tot] = hd[v]; to[tot] = u; fl[tot] = 0; hd[v] = tot++;
 58 }
 59 
 60 int dep[siz];
 61 
 62 inline bool bfs(void)
 63 {
 64     static int que[siz], head, tail;
 65     
 66     for (int i = s; i <= t; ++i)dep[i] = 0;
 67     
 68     dep[que[head = 0] = s] = tail = 1;
 69     
 70     while (head != tail)
 71     {
 72         int u = que[head++], v;
 73         
 74         for (int i = hd[u]; ~i; i = nt[i])
 75             if (!dep[v = to[i]] && fl[i])
 76                 dep[que[tail++] = v] = dep[u] + 1;
 77     }
 78     
 79     return dep[t];
 80 }
 81 
 82 int cur[siz];
 83 
 84 inline int min(int a, int b)
 85 {
 86     return a < b ? a : b;
 87 }
 88 
 89 int dfs(int u, int f)
 90 {
 91     if (u == t || !f)
 92         return f;
 93         
 94     int used = 0, flow, v;
 95     
 96     for (int i = cur[u]; ~i; i = nt[i])
 97         if (dep[v = to[i]] == dep[u] + 1 && fl[i])
 98         {
 99             flow = dfs(v, min(fl[i], f - used));
100             
101             used += flow;
102             fl[i] -= flow;
103             fl[i^1] += flow;
104             
105             if (used == f)
106                 return f;
107             
108             if (fl[i])
109                 cur[u] = i;
110         }
111         
112     if (!used)
113         dep[u] = 0;
114     
115     return used;
116 }
117 
118 inline int maxFlow(void)
119 {
120     int maxFlow = 0, newFlow;
121     
122     while (bfs())
123     {
124         for (int i = s; i <= t; ++i)
125             cur[i] = hd[i];
126             
127         while (newFlow = dfs(s, inf))
128             maxFlow += newFlow;
129     }
130     
131     return maxFlow;
132 }
133 
134 inline int pos(int x, int y)
135 {
136     return m * (x - 1) + y;
137 }
138 
139 const int mv[4][2] = 
140 {
141     {0, +1},
142     {0, -1},
143     {-1, 0},
144     {+1, 0}
145 };
146 
147 signed main(void)
148 {
149     freopen("Seal.in", "r", stdin);
150     freopen("Seal.out", "w", stdout);
151     
152     n = nextInt();
153     m = nextInt();
154     
155     
156     for (int i = 1; i <= n; ++i)
157         for (int j = 1; j <= m; ++j)
158             g[i][j] = next();
159             
160     s = 0, t = n * m * 2 + 1;
161             
162     for (int i = s; i <= t; ++i)
163         hd[i] = -1;
164     
165     for (int i = 1; i <= n; ++i)
166         for (int j = 1; j <= m; ++j)
167             if (g[i][j])
168             {
169                 if ((i + j) & 1)
170                 {
171                     if (i & 1)
172                         add(s, pos(i, j), 1);
173                     else
174                         add(pos(i, j), t, 1);
175                 }
176                 else
177                 {
178                     for (int k = 0; k < 4; ++k)
179                     {
180                         int x = i + mv[k][0];
181                         int y = j + mv[k][1];
182                         
183                         if (x < 1 || x > n)
184                             continue;
185                         if (y < 1 || y > m)
186                             continue;
187                         if (!g[x][y])
188                             continue;
189                             
190                         if (x & 1)
191                             add(pos(x, y), pos(i, j), 1);
192                         else
193                             add(pos(i, j) + n*m, pos(x, y), 1);
194                             
195                         add(pos(i, j), pos(i, j) + n*m, 1);
196                     }
197                 }
198             }
199             
200     printf("%d
", maxFlow());
201             
202     return fclose(stdin), fclose(stdout), 0;
203 }

T2 Repair

 依旧不会做,然后听LH大爷讲题解,讲完就怀疑自己智商了……

有点像是可行流问题(本来就是可行流好嘛),只是需要分类讨论一下。

对于一条边,如果一开始流量$F$大于$C$,即$F gt C$,那么有如下情况:

如果最后流量$X$大于$F$,即$X gt F gt C$,那么有$fare=X-F+X-C$,如果设$K=F-C$,有$fare=K+2(X-F)$.

如果最后流量$X$在$F$和$C$之间,即$F gt X gt C$,那么有$fare=F-X+X-C=K$.

如果最后流量$X$小于$C$,即$F gt C gt X$,那么有$fare=F-X=K+C-X$.

不难总结出对于这类边的建新边方式:

先将$K$直接统计到答案之中,然后从$u$向$v$连容量为$INF$的边,费用为$2$,从$v$向$u$连容量为$F-C$的边,费用为$0$,从$v$向$u$连容量为$C$的边,费用为$1$。

对于一条边,如果一开始流量$F$小于$C$,即$F lt C$,那么有如下情况:

如果最后流量$X$大于$C$,即$X gt C gt F$,那么有$fare=X-C+X-F$。

如果最后流量$X$在$C$和$F$之间,即$C gt X gt F$,那么有$fare=X-F$。

如果最后流量$X$小于$F$,即$C gt F gt X$,那么有$fare=F-X$。

不难总结出对这类边的建新边方式:

从$u$向$v$连容量为$C-F$的边,费用为$1$,从$u$向$v$连容量为$INF$的边,费用为$2$,从$v$向$u$连容量为$F$的边,费用为$1$。

最后为了满足流量守恒,设立新的源汇点,源点向流入量多的点连边,流出量多的点向汇点连边,原汇点向原源点连无穷的边,跑最小费用最大流即可。

  1 #include <cstdio>
  2 
  3 inline int nextChar(void) {
  4     const int siz = 1024;
  5     
  6     static char buf[siz];
  7     static char *hd = buf + siz;
  8     static char *tl = buf + siz;
  9     
 10     if (hd == tl)
 11         fread(hd = buf, 1, siz, stdin);
 12         
 13     return *hd++;
 14 }
 15  
 16 inline int nextInt(void) {
 17     register int ret = 0;
 18     register int neg = false;
 19     register int bit = nextChar();
 20     
 21     for (; bit < 48; bit = nextChar())
 22         if (bit == '-')neg ^= true;
 23         
 24     for (; bit > 47; bit = nextChar())
 25         ret = ret * 10 + bit - 48;
 26         
 27     return neg ? -ret : ret;
 28 }
 29 
 30 const int siz = 5000005;
 31 const int inf = 1000000007;
 32 
 33 int n, m;
 34 int answer;
 35 int del[siz];
 36 
 37 int tot;
 38 int s, t;
 39 int hd[siz];
 40 int to[siz];
 41 int fl[siz];
 42 int vl[siz];
 43 int nt[siz];
 44 
 45 inline void add(int u, int v, int f, int w)
 46 {
 47 //    printf("add %d %d %d %d
", u, v, f, w);
 48     nt[tot] = hd[u]; to[tot] = v; fl[tot] = f; vl[tot] = +w; hd[u] = tot++;
 49     nt[tot] = hd[v]; to[tot] = u; fl[tot] = 0; vl[tot] = -w; hd[v] = tot++;
 50 }
 51 
 52 int dep[siz];
 53 
 54 inline bool bfs(void)
 55 {
 56     static int que[siz], head, tail;
 57     
 58     for (int i = s; i <= t; ++i)dep[i] = 0;
 59     
 60     dep[que[head = 0] = s] = tail = 1;
 61     
 62     while (head != tail)
 63     {
 64         int u = que[head++], v;
 65         
 66         for (int i = hd[u]; ~i; i = nt[i])
 67             if (!dep[v = to[i]] && fl[i] && !vl[i])
 68                 dep[que[tail++] = v] = dep[u] + 1;
 69     }
 70     
 71     return dep[t];
 72 }
 73 
 74 int cur[siz];
 75 
 76 inline int min(int a, int b)
 77 {
 78     return a < b ? a : b;
 79 }
 80 
 81 int dfs(int u, int f)
 82 {
 83     if (u == t || !f)
 84         return f;
 85         
 86     int used = 0, flow, v;
 87     
 88     for (int i = hd[u]; ~i; i = nt[i])
 89         if (dep[v = to[i]] == dep[u] + 1 && fl[i] && !vl[i])
 90         {
 91             flow = dfs(v, min(fl[i], f - used));
 92             
 93             used += flow;
 94             fl[i] -= flow;
 95             fl[i^1] += flow;
 96             
 97             if (used == f)
 98                 return f;
 99                 
100             if (fl[i])
101                 cur[u] = i;
102         }
103         
104     if (!used)
105         dep[u] = 0;
106     
107     return used;
108 }
109 
110 inline void maxFlow(void)
111 {
112     while (bfs())
113         while (dfs(s, inf));
114 }
115 
116 int dis[siz];
117 int pre[siz];
118 
119 inline bool spfa(void)
120 {
121     static int que[siz];
122     static int inq[siz];
123     static int head, tail;
124     
125     for (int i = s; i <= t; ++i)
126         inq[i] = 0, dis[i] = inf;
127         
128     head = 0, tail = 0;
129     que[tail++] = s;
130     pre[s] = -1;
131     dis[s] = 0;
132     
133     while (head != tail)
134     {
135         int u = que[head++], v; inq[u] = 0;
136         
137         for (int i = hd[u]; ~i; i = nt[i])
138             if (dis[v = to[i]] > dis[u] + vl[i] && fl[i])
139             {
140                 dis[v] = dis[u] + vl[i], pre[v] = i ^ 1;
141                 if (!inq[v])
142                     inq[que[tail++] = v] = 1;
143             }
144     }
145     
146     return dis[t] < inf;
147 }
148 
149 inline void minCost(void)
150 {
151     while (spfa())
152     {
153         int flow = inf;
154         
155         for (int i = pre[t]; ~i; i = pre[to[i]])
156             if (fl[i ^ 1] < flow)flow = fl[i ^ 1];
157             
158         for (int i = pre[t]; ~i; i = pre[to[i]])
159             fl[i] += flow, fl[i ^ 1] -= flow;
160             
161         answer += dis[t] * flow;
162     }
163 }
164 
165 signed main(void)
166 {
167     freopen("Repair.in", "r", stdin);
168     freopen("Repair.out", "w", stdout);
169     
170     n = nextInt();
171     m = nextInt();
172     
173     s = 0, t = n + 1;
174     
175     for (int i = s; i <= t; ++i)
176         hd[i] = -1;
177     
178     for (int i = 1; i <= m; ++i)
179     {
180         int u = nextInt();
181         int v = nextInt();
182         int c = nextInt();
183         int f = nextInt();
184         
185         del[u] += f;
186         del[v] -= f;
187         
188         if (f <= c)
189         {
190             add(u, v, c - f, 1);
191             add(u, v, inf, 2);
192             add(v, u, f, 1);
193         }
194         else
195         {
196             answer += f - c;
197             add(u, v, inf, 2);
198             add(v, u, f - c, 0);
199             add(v, u, c, 1);
200         }
201     }
202     
203     add(n, 1, inf, 0);
204     
205     for (int i = 1; i <= n; ++i)
206         if (del[i] < 0)
207             add(s, i, -del[i], 0);
208         else if (del[i] > 0)
209             add(i, t, del[i], 0);
210             
211     maxFlow();
212     
213     minCost();
214     
215     printf("%d
", answer);
216     
217     return fclose(stdin), fclose(stdout), 0;
218 }

T3 Flow

依旧不会,看到$G(f)$函数就是mengbi的。

GZZ神犇说,MCMF中每次增广出来的路径,就是$C(f)$关于$F(f)$函数中的一段一次函数…… $OTZ GZZ$

然后,分步跑出来每一段的函数,求函数上距离(maxFlow,0)点的最近距离即可,我怎么这么蠢,23333

  1 #include <cstdio>
  2 
  3 template <class T>
  4 inline T min(T a, T b)
  5 {
  6     return a < b ? a : b;
  7 }
  8 
  9 template <class T>
 10 T gcd(T a, T b)
 11 {
 12     return b ? gcd(b, a % b) : a;
 13 }
 14 
 15 template <class T>
 16 inline T sqr(T x)
 17 {
 18     return x * x;
 19 }
 20 
 21 #define int long long
 22 
 23 inline int nextChar(void) {
 24     const int siz = 1024;
 25     
 26     static char buf[siz];
 27     static char *hd = buf + siz;
 28     static char *tl = buf + siz;
 29     
 30     if (hd == tl)
 31         fread(hd = buf, 1, siz, stdin);
 32         
 33     return *hd++;
 34 }
 35  
 36 inline int nextInt(void) {
 37     register int ret = 0;
 38     register int neg = false;
 39     register int bit = nextChar();
 40     
 41     for (; bit < 48; bit = nextChar())
 42         if (bit == '-')neg ^= true;
 43         
 44     for (; bit > 47; bit = nextChar())
 45         ret = ret * 10 + bit - 48;
 46         
 47     return neg ? -ret : ret;
 48 }
 49 
 50 const int siz = 500005;
 51 const int inf = 1000000007;
 52 
 53 int n, m;
 54 
 55 int tot;
 56 int s, t;
 57 int hd[siz];
 58 int nt[siz];
 59 int fl[siz];
 60 int vl[siz];
 61 int to[siz];
 62 
 63 inline void add(int u, int v, int f, int w)
 64 {
 65     nt[tot] = hd[u]; to[tot] = v; vl[tot] = +w; fl[tot] = f; hd[u] = tot++;
 66     nt[tot] = hd[v]; to[tot] = u; vl[tot] = -w; fl[tot] = 0; hd[v] = tot++;
 67 }
 68 
 69 int dep[siz];
 70 
 71 inline bool bfs(void)
 72 {
 73     static int que[siz], head, tail;
 74     
 75     for (int i = 1; i <= n; ++i)dep[i] = 0;
 76     
 77     dep[que[head = 0] = s] = tail = 1;
 78     
 79     while (head != tail)
 80     {
 81         int u = que[head++], v;
 82         
 83         for (int i = hd[u]; ~i; i = nt[i])
 84             if (!dep[v = to[i]] && fl[i])
 85                 dep[que[tail++] = v] = dep[u] + 1;
 86     }
 87     
 88     return dep[t];
 89 }
 90 
 91 int cur[siz];
 92 
 93 int dfs(int u, int f)
 94 {
 95     if (u == t || !f)
 96         return f;
 97         
 98     int used = 0, flow, v;
 99     
100     for (int i = cur[u]; ~i; i = nt[i])
101         if (dep[v = to[i]] == dep[u] + 1 && fl[i])
102         {
103             flow = dfs(v, min(fl[i], f - used));
104             
105             used += flow;
106             fl[i] -= flow;
107             fl[i^1] += flow;
108             
109             if (used == f)
110                 return f;
111             
112             if (fl[i])
113                 cur[u] = i;
114         }
115         
116     if (!used)
117         dep[u] = 0;
118     
119     return used;
120 }
121 
122 inline int Dinic(void)
123 {
124     int maxFlow = 0, newFlow;
125     
126     while (bfs())
127     {
128         for (int i = 1; i <= n; ++i)
129             cur[i] = hd[i];
130             
131         while (newFlow = dfs(s, inf))
132             maxFlow += newFlow;
133     }
134     
135     return maxFlow;
136 }
137 
138 int dis[siz];
139 int pre[siz];
140 
141 inline bool spfa(void)
142 {
143     static int que[siz];
144     static int inq[siz];
145     static int head, tail;
146     
147     for (int i = 1; i <= n; ++i)
148         dis[i] = inf, inq[i] = 0;
149         
150     head = 0, tail = 0;
151     que[tail++] = s;
152     pre[s] = -1;
153     dis[s] = 0;
154     inq[s] = 1;
155     
156     while (head != tail)
157     {
158         int u = que[head++], v; inq[u] = 0;
159         
160         for (int i = hd[u]; ~i; i = nt[i])
161             if (fl[i] && dis[v = to[i]] > dis[u] + vl[i])
162             {
163                 dis[v] = dis[u] + vl[i], pre[v] = i ^ 1;
164                 if (!inq[v])inq[que[tail++] = v] = 1;
165             }
166     }
167     
168     return dis[t] < inf;
169 }
170 
171 signed main(void)
172 {
173     freopen("Flow.in", "r", stdin);
174     freopen("Flow.out", "w", stdout);
175     
176     n = nextInt();
177     m = nextInt();
178     s = nextInt();
179     t = nextInt();
180     
181     for (int i = 1; i <= n; ++i)
182         hd[i] = -1;
183         
184     for (int i = 1; i <= m; ++i)
185     {
186         int x = nextInt();
187         int y = nextInt();
188         int u = nextInt();
189         int c = nextInt();
190         add(x, y, u, c);
191     }
192     
193     int maxFlow = Dinic();
194     
195     for (int i = 0; i < tot; i += 2)
196         fl[i] += fl[i ^ 1], fl[i ^ 1] = 0;
197     
198     int C = 0, F = maxFlow;
199     
200     while (spfa())
201     {
202         int w = dis[t];
203         
204         int flow = inf;
205         
206         for (int i = pre[t]; ~i; i = pre[to[i]])
207             if (fl[i ^ 1] < flow)
208                 flow = fl[i ^ 1];
209                 
210         if (F - w * C >= flow * (sqr(w) + 1)) 
211         {
212             for (int i = pre[t]; ~i; i = pre[to[i]])
213                 fl[i] += flow, fl[i ^ 1] -= flow;
214                 
215             F -= flow, C += flow * dis[t];
216         }
217         else
218         {
219             if (F > w * C)
220             {
221                 int r = sqr(w * F + C);
222                 int d = sqr(w) + 1;
223                 int g = gcd(r, d);
224                 printf("%lld/%lld
", r / g, d / g);
225             }
226             else
227                 printf("%lld/%lld
", sqr(C) + sqr(F), 1LL);
228             
229             goto end;
230         }
231     }
232     
233     printf("%lld/%lld
", sqr(C) + sqr(F), 1LL);
234     
235 end:return fclose(stdin), fclose(stdout), 0;
236 }

@Author: YouSiki

原文地址:https://www.cnblogs.com/yousiki/p/6253101.html