写在前面:SDOI2016 Round1滚粗后蒟蒻开始做网络流来自我拯救(2016-04-11再过几天就要考先修课,现在做网络流24题貌似没什么用←退役节奏)
做的题目将附上日期,见证我龟速刷题。
1.飞行员配对方案问题 2016-04-11
二分图最大匹配问题,更新了一下$Dinic$模板,带上了当前弧优化和多路增广。这道题输出方案有很多种,可是没有special judge,所以没有A,但方案数是对的。合法的输出方案只能用匈牙利算法解决。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 1003; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue<int> q; bool vis[N]; int point[N], cap[N], nxt[N], to[N], d[N], cur[N], S, T, cnt = 1; bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); d[S] = 0; vis[S] = 1; int u, i; while (!q.empty()) { u = q.front(); q.pop(); for(i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int f, flow = 0; for(int &i = cur[u]; i; i = nxt[i]) if (d[u] + 1 == d[to[i]] && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int flow = 0, i; while (BFS()) { for(i = 1; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, 0x7fffffff); } return flow; } void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } void findpair(int x) { for(int i = point[x]; i; i = nxt[i]) if (cap[i] == 0 && to[i] != S) {printf("%d %d ", x, to[i]); break;} } int main() { int n, m; read(n); read(m); S = n + m + 1; T = S + 1; for(int i = 1; i <= n; ++i) ins(S, i, 1), ins(i, S, 0); for(int i = n + 1; i <= n + m; ++i) ins(i, T, 1), ins(T, i, 0); int u, v; read(u); read(v); while (u != -1 && v != -1) { ins(u, v, 1); ins(v, u, 0); read(u); read(v); } printf("%d ", Dinic()); for(int i = 1; i <= n; ++i) findpair(i); return 0; }
2.太空飞行计划问题 2016-04-13
典型的最大权闭合图问题,可是还是要输出方案!!!制杖地卡了1h+因为把n+m打成了n+m+1,然后发现还是会WA两个点。最后百度得知数据是不盈利也不亏损的项目还要加上,如果要这么做还得删边balabalabala。我不想再改了,所以就这样吧。我现在感觉什么都需要special judge,因为我太弱了hhh
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 1003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } bool vis[N]; queue <int> q; int point[N], nxt[N], to[N], cap[N], d[N], cur[N], S, T, cnt = 1, n, m, Qsum = 0, Qmincut; void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); vis[S] = 1; d[S] = 0; int u, i; while (!q.empty()) { u = q.front(); q.pop(); for(i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; q.push(to[i]); vis[to[i]] = 1; } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int f, flow = 0; for(int &i = cur[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int flow = 0, i; while (BFS()) { for(i = 1; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, inf); } return flow; } void Q() { for(int i = 1; i <= m; ++i) if (vis[i]) printf("%d ", i); puts(""); for(int i = m + 1; i <= m + n; ++i) if (vis[i]) printf("%d ", i - m); printf(" %d ", Qsum - Qmincut); } int main() { read(m); read(n); S = m + n + 1; T = S + 1; int num; char c; for(int i = 1; i <= m; ++i) { read(num); Qsum += num; ins(S, i, num); ins(i, S, 0); c = getchar(); while(1) { num = 0; for(; c < '0' || c > '9'; c = getchar()) if (c == ' ') break; if (c == ' ') break; for(; c >= '0' && c <= '9'; c = getchar()) num = num * 10 + c - '0'; num = num + m; ins(i, num, inf); ins(num, i, 0); } } for(int i = m + 1; i <= m + n; ++i) { read(num); ins(i, T, num); ins(T, i, 0); } Qmincut = Dinic(); Q(); return 0; }
3.最小路径覆盖问题 2016-04-13
二分图最大匹配问题。遇到求“最小”,因为我们求的都是最大流,所以应该往补集转化的方向思考,“总的”-“最大的”=“最小的”。这种题还应该注意一个地方,虽然在这里用不着,但要处处留心:最小路径覆盖问题值得注意的地方
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 20003; const int inf = 0x7fffffff; queue <int> q; bool vis[N]; int point[N], cur[N], nxt[N], to[N], cap[N], d[N], n, m, S, T, cnt = 1, Qmincut; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); d[S] = 0; vis[S] = 1; while (!q.empty()) { int u = q.front(), i; q.pop(); for(i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int f, flow = 0; for(int &i = point[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int i, flow = 0; while (BFS()) { for(i = 1; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, inf); } return flow; } void QQ(int x) { vis[x] = 1; printf("%d ", x); for(int i = point[x]; i; i = nxt[i]) if (cap[i] < inf && n < to[i] && to[i] <= n + n) QQ(to[i] - n); } void Q() { memset(vis, 0, sizeof(vis)); for(int i = 1; i <= n; ++i) if (!vis[i]) QQ(i), puts(""); printf("%d ", n - Qmincut); } int main() { read(n); read(m); int u, v; S = n + n + 1; T = S + 1; for(int i = 1, j = n + 1; i <= n; ++i, ++j) ins(S, i, 1), ins(i, S, 0), ins(j, T, 1), ins(T, j, 0); for(int i = 1; i <= m; ++i) { read(u); read(v); v += n; ins(u, v, inf); ins(v, u, 0); } Qmincut = Dinic(); Q(); return 0; }
4.魔术球问题 2016-04-17
最小路径覆盖问题,想了好久,看完题解后还是想了好久QuQ。当时主要是不明白为什么满足单调性,后来才发现DAG上不断加边,最小路径覆盖数肯定是不减的,当时好制杖啊QAQ。写完后更制杖的是我发现我又需要special judge!!!怎么我现在弱到什么都需要special judge!!!PS:昨天北大先修课乙烷,xyx考得最好但是他没有用正规的比赛号交题,,,
#include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c= getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], nxt[N << 1], to[N << 1], cap[N << 1], d[N], S, T, cnt = 1, ans = 0, n, Q = 0; bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for(int i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int f, flow = 0; for(int i = point[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } void Dinic() { while (BFS()) ans -= DFS(S, 0x7fffffff); } void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } void Qwork(int x) { printf("%d ", x); vis[x] = 1; for(int i = point[x]; i; i = nxt[i]) if (!cap[i] && to[i] > 5000 && to[i] < 5000 + Q && !vis[to[i] - 5000]) Qwork(to[i] - 5000); } int main() { read(n); S = 0; T = 10002; while (1) { ++ans; ++Q; for(int i = 1; i < Q; ++i) if (sqrt(i + Q) == (int)(sqrt(i + Q))) ins(i, Q + 5000, 1), ins(Q + 5000, i, 0); ins(S, Q, 1); ins(Q, S, 0); ins(Q + 5000, T, 1); ins(T, Q + 5000, 0); Dinic(); if (ans > n) { printf("%d ", Q - 1); break; } } memset(vis, 0, sizeof(vis)); for(int i = 1; i < Q; ++i) if (!vis[i]) Qwork(i), puts(""); return 0; }
5.圆桌问题 2016-04-17
很简单的二分图多重匹配,写完后我发现我又需要special judge了QAQ
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], cur[N], nxt[N << 1], to[N << 1], cap[N << 1], S, T, cnt = 1, d[N]; bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for(int i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int f, flow = 0; for(int &i = cur[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int flow = 0; while (BFS()) { for(int i = 0; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, 0x7fffffff); } return flow; } void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } int main() { int n, m, x, Qsum = 0; read(m); read(n); S = 0; T = m + n + 1; for(int i = 1; i <= m; ++i) read(x), ins(S, i, x), ins(i, S, 0), Qsum += x; for(int i = m + 1; i < T; ++i) read(x), ins(i, T, x), ins(T, i, 0); for(int i = 1; i <= m; ++i) for(int j = m + 1; j < T; ++j) ins(i, j, 1), ins(j, i, 0); int Q = Dinic(); if (Q == Qsum) { puts("1"); for(int i = 1; i <= m; ++i) { cnt = 0; for(int tmp = point[i]; tmp; tmp = nxt[tmp]) if (!cap[tmp] && to[tmp] > m && to[tmp] < T) d[++cnt] = to[tmp] - m; for(; cnt; --cnt) printf("%d ", d[cnt]); puts(""); } } else puts("0"); return 0; }
6.最长递增子序列问题 2016-04-17
分层图思想可以保证走的每条路都是最长的,统计最大流就可以了,对于第三问放宽$X_1,X_n$的限制即可。还有一个地方我卡了好久,就是$inf$设置成了$0x7fffffff$,这样会出现爆int的情况,只需把inf调小一点,输出时特判一下就没了,,,TwT我卡了3h+啊
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x = getint() using namespace std; const int N = 100003; const int inf = 1E9; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], cur[N], d[N], nxt[N << 1], to[N << 1], cap[N << 1], S, T, cnt = 1; bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); d[S] = 0; vis[S] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for(int i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int f, flow = 0; for(int &i = cur[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int i, flow = 0; while (BFS()) { for(i = 0; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, inf); } return flow; } int a[N], f[N]; void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } int main() { int n; read(n); for(int i = 1; i <= n; ++i) read(a[i]); f[n] = 1; for(int i = n - 1; i > 0; --i) { f[i] = 1; for(int j = n; j > i; --j) if (a[i] <= a[j] && f[j] + 1 > f[i]) f[i] = f[j] + 1; } int k = 0; for(int i = 1; i <= n; ++i) k = max(k, f[i]); printf("%d ", k); S = 0; T = (n << 1) + 1; for(int i = 1; i <= n; ++i) { ins(i, i + n, 1), ins(i + n, i, 0); if (f[i] == k) ins(S, i, 1), ins(i, S, 0); if (f[i] == 1) ins(i + n, T, 1), ins(T, i + n, 0); } for(int i = 1; i < n; ++i) for(int j = i + 1; j <= n; ++j) if (a[i] <= a[j] && f[i] == f[j] + 1) ins(i + n, j, 1), ins(j, i + n, 0); int Q = Dinic(); printf("%d ", Q); memset(point, 0, sizeof(point)); cnt = 1; for(int i = 1; i <= n; ++i) { if (i == 1 || i == n) { ins(i, i + n, inf), ins(i + n, i, 0); if (f[i] == k) ins(S, i, inf), ins(i, S, 0); if (f[i] == 1) ins(i + n, T, inf), ins(T, i + n, 0); } else { ins(i, i + n, 1), ins(i + n, i, 0); if (f[i] == k) ins(S, i, 1), ins(i, S, 0); if (f[i] == 1) ins(i + n, T, 1), ins(T, i + n, 0); } } for(int i = 1; i < n; ++i) for(int j = i + 1; j <= n; ++j) if (a[i] <= a[j] && f[i] == f[j] + 1) ins(i + n, j, 1), ins(j, i + n, 0); Q = Dinic(); printf("%d ", Q > inf ? n : Q); return 0; }
7.试题库问题 2016-04-17
水题,不过我又需要special judge了QuQ
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 10003; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], cur[N], nxt[N << 1], to[N << 1], S, T, cnt = 1, d[N], cap[N << 1]; bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); d[S] = 0; vis[S] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for(int i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int flow = 0, f; for(int &i = cur[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int flow = 0; while (BFS()) { for(int i = 0; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, 0x7fffffff); } return flow; } void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } int main() { int k, n, m = 0, x, p; read(k); read(n); S = 0; T = k + n + 1; for(int i = 1; i <= k; ++i) read(x), ins(S, i, x), ins(i, S, 0), m += x; for(int i = 1; i <= n; ++i) { read(p); for(int j = 1; j <= p; ++j) { read(x); ins(x, i + k, 1); ins(i + k, x, 0); } } for(int i = k + 1; i < T; ++i) ins(i, T, 1), ins(T, i, 0); int Q = Dinic(); if (Q == m) { for(int i = 1; i <= k; ++i) { printf("%d:", i); for(int tmp = point[i]; tmp; tmp = nxt[tmp]) if (!cap[tmp] && to[tmp] > k && to[tmp] < T) printf(" %d", to[tmp] - k); puts(""); } } else puts("No Solution!"); return 0; }
8.机器人路径规划问题
貌似这道题挺麻烦,CTSC和省选Round2前没有太多时间,暂时略过,省选二轮滚粗后再来看QAQ
9.方格取数问题 2016-04-18
因为最大独立点集+最小点覆盖集=总点数,那么最大点权独立集+最小点权覆盖集=总点权和。我们只需求最小点权覆盖集就可以了。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int inf = 0x7fffffff; const int N = 100003; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], cur[N], nxt[N << 1], cap[N << 1], to[N << 1], S, T, cnt = 1, d[N]; bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for(int i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int flow = 0, f; for(int &i = cur[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int flow = 0; while (BFS()) { for(int i = 0; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, inf); } return flow; } int a[53][53]; void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } void QQ(int Qsum) { int Q = Dinic(); Q = Qsum - Q; printf("%d ", Q); } int main() { int n, m, Qsum = 0; read(m); read(n); for(int i = 1; i <= m; ++i) for(int j = 1; j <= n; ++j) read(a[i][j]), Qsum += a[i][j]; S = 0; T = n * m + 1; for(int i = 1; i <= m; ++i) for(int j = 1; j <= n; ++j) if ((i + j) % 2 == 0) { ins(S, (i - 1) * n + j, a[i][j]); ins((i - 1) * m + j, S, 0); if (i > 1) { ins((i - 1) * n + j, (i - 2) * n + j, inf); ins((i - 2) * n + j, (i - 1) * n + j, 0); } if (j > 1) { ins((i - 1) * n + j, (i - 1) * n + j - 1, inf); ins((i - 1) * n + j - 1, (i - 1) * n + j, 0); } if (i < m) { ins((i - 1) * n + j, i * n + j, inf); ins(i * n + j, (i - 1) * n + j, 0); } if (j < n) { ins((i - 1) * n + j, (i - 1) * n + j + 1, inf); ins((i - 1) * n + j + 1, (i - 1) * n + j, 0); } } for(int i = 1; i <= m; ++i) for(int j = 1; j <= n; ++j) if ((i + j) % 2 == 1) { ins((i - 1) * n + j, T, a[i][j]); ins(T, (i - 1) * n + j, 0); } QQ(Qsum); return 0; }
10.餐巾计划问题 2016-04-18
最小费用最大流问题。在保证最大流的前提下求最小费用,建图我就不细说了,主要是把买的和洗的餐巾分为两部分,网上有很多题解。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], nxt[N << 1], to[N << 1], cap[N << 1], S, T, cnt = 1; int d[N], w[N << 1], from[N << 1], pre[N << 1]; bool spfa(int s, int t) { for(int i = 0; i <= t; ++i) vis[i] = 0, d[i] = inf; d[s] = 0; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[t] != inf; } int mcmf(int s, int t) { int ret = 0, f, u; while (spfa(s, t)) { f = inf; for(u = t; u != s; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = t; u != s; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += f * d[t]; } return ret; } int nn, p, m, f, n, s, r[N]; void ins(int x, int y, int z, int zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } int main() { read(nn); read(p); read(m); read(f); read(n); read(s); for(int i = 1; i <= nn; ++i) read(r[i]); S = 0; T = (nn << 1) + 1; for(int i = 1; i <= nn; ++i) { ins(S, i, r[i], 0); ins(i, S, 0, 0); ins(i + nn, T, r[i], 0); ins(T, i + nn, 0, 0); ins(S, i + nn, inf, p); ins(i + nn, S, 0, -p); if (i < nn) { ins(i, i + 1, inf, 0); ins(i + 1, i, 0, 0); } if (i + m <= nn) { ins(i, i + m + nn, inf, f); ins(i + m + nn, i, 0, -f); } if (i + n <= nn) { ins(i, i + n + nn, inf, s); ins(i + n + nn, i, 0, -s); } } int Q = mcmf(S, T); printf("%d ", Q); return 0; }
11.航空路线问题 2016-04-18
裸拆点最小费用最大流,我打错了MCMF模板,查了1h的错TwT。在第二组数据吐血QAQ,只好面向数据编程,,,还有I need special judge again!!!
#include<map> #include<queue> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } map <string, int> ma; queue <int> q; bool vis[N]; int point[N], nxt[N << 1], to[N << 1], cap[N << 1], d[N]; int S, T, cnt = 1, w[N << 1], from[N << 1], pre[N]; bool spfa() { for(int i = 0; i <= T; ++i) vis[i] = 0, d[i] = inf; q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[T] != inf; } int mcmf() { int ret = 0, f, u; while (spfa()) { f = inf; for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += f * d[T]; } return ret; } int n, v, x, y; string s1, s2, str[N]; void ins(int x, int y, int z, int zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } void QQ(int x) { cout<< str[x] << endl; for(int i = point[x + n]; i; i = nxt[i]) if (!cap[i] && !vis[to[i]] && to[i] > 0 && to[i] <= n) {QQ(to[i]); break;} } void QQQ(int x) { if (x == n) { QQ(1); return; } vis[x] = 1; for(int i = point[x + n]; i; i = nxt[i]) if (!cap[i] && to[i] > 0 && to[i] <= n) {QQQ(to[i]); break;} cout << str[x] <<endl; } int main() { read(n); read(v); ma.clear(); for(int i = 1; i <= n; ++i) cin >> str[i], ma[str[i]] = i; S = 1; T = n << 1; for(int i = 1; i <= n; ++i) if (i == 1 || i == n) { ins(i, i + n, 2, -1); ins(i + n, i, 0, 1); } else { ins(i, i + n, 1, -1); ins(i + n, i, 0, 1); } for(int i = 1; i <= v; ++i) { cin >> s1 >> s2; x = ma[s1]; y = ma[s2]; ins(x + n, y, 1, 0); ins(y, x + n, 0, 0); } int Q = mcmf(); if (cap[2] && n != 3) puts("No Solution!"); else printf("%d ", n != 3 ? - Q - 2 : -Q), memset(vis, 0, sizeof(vis)), QQQ(1); return 0; }
12.软件补丁问题 2016-04-18
因为只有20种错误,考虑状态压缩然后spfa最短路,这还是网络流吗,,,
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 2000003; char a[23], b[23]; bool vis[N]; queue <int> q; int b1[N], b2[N], f1[N], f2[N], cost[N], n, m, d[N], inf; int spfa(int s, int t) { memset(d, 127, sizeof(d)); inf = d[t]; d[s] = 0; q.push(s); vis[s] = 0; while (!q.empty()) { int x = q.front(); q.pop(); vis[x] = 0; for(int i = 1; i <= m; ++i) if ((x | b1[i]) == x && (x & b2[i]) == 0) { int y = x & (~ f1[i]); y |= f2[i]; if (d[y] > d[x] + cost[i]) { d[y] = d[x] + cost[i]; if (!vis[y]) { vis[y] = 1; q.push(y); } } } } return d[t] == inf ? 0 : d[t]; } int main() { memset(b1, 0, sizeof(b1)); memset(b2, 0, sizeof(b2)); memset(f1, 0, sizeof(f1)); memset(f2, 0, sizeof(f2)); scanf("%d%d", &n, &m); for(int i = 1; i <= m; ++i) { scanf("%d %s %s", &cost[i], a, b); for(int j = 0; j < strlen(a); ++j) if (a[j] == '+') b1[i] |= 1 << j; else if (a[j] == '-') b2[i] |= 1 << j; for(int j = 0; j < strlen(b); ++j) if (b[j] == '+') f2[i] |= 1 << j; else if (b[j] == '-') f1[i] |= 1 << j; } printf("%d ", spfa((1 << n) - 1, 0)); return 0; }
13.星际转移问题 2016-04-18
将每天转化为分层图,然后每天都跑最大流,若最大流大于等于k,则输出答案。特殊情况我还是面向数据编程,,,我怎么这么弱QAQ
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 2000003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } bool vis[N]; queue <int> q; int point[N], cur[N], nxt[N], cap[N], d[N], to[N], S, T, cnt = 1; bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for(int i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int flow = 0, f; for(int &i = cur[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int flow = 0; while (BFS()) { for(int i = 0; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, inf); } return flow; } struct node {int r, num, a[103];} B[203]; int n, m, k; void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } void mk(int &x) {x = (x == 0 ? n + 1 : (x == -1 ? n + 2 : x));} int main() { read(n); read(m); read(k); S = 0; T = N - 3; for(int i = 1; i <= m; ++i) { read(B[i].r); read(B[i].num); for(int j = 1; j <= B[i].num; ++j) read(B[i].a[j]), mk(B[i].a[j]); B[i].a[0] = B[i].a[B[i].num]; } int earth = n + 1, moon = n + 2, gh = moon, Q = 0; ins(S, earth, k), ins(earth, S, 0); for(int Day = 1; Day <= 30; ++Day) { for(int i = 1; i < gh; ++i) { ins((Day - 1) * gh + i, Day * gh + i, inf); ins(Day * gh + i, (Day - 1) * gh + i, 0); } ins(Day * gh + moon, T, inf), ins(T, Day * gh + moon, 0); for(int i = 1; i <= m; ++i) { int last = B[i].a[Day % B[i].num], now = B[i].a[(Day + 1) % B[i].num]; ins((Day - 1) * gh + last, Day * gh + now, B[i].r); ins(Day * gh + now, (Day - 1) * gh + last, 0); } Q += Dinic(); if (Q >= k) { printf("%d ", Day); break; } } if (Q < k) puts("0"); return 0; }
14.孤岛营救问题 2016-04-18
在分层图上spfa,不是网络流,,,以后是不是遇到水的数据就应该考虑不同寻常的做法。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 2000003; const int inf = 2139062143; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int cnt = 1, point[N], nxt[N], to[N], w[N], d[N]; void spfa(int s) { memset(vis, 0, sizeof(vis)); memset(d, 127, sizeof(d)); q.push(s); vis[s] = 1; d[s] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } } int n, m, p, k, S, map[16][16][16][16]; void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; w[cnt] = z; point[x] = cnt; } int main() { read(n); read(m); read(p); read(k); memset(map, -1, sizeof(map)); int x1, x2, y1, y2, z, dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0}; for(int i = 1; i <= k; ++i) { read(x1); read(y1); read(x2); read(y2); read(z); map[x1][y1][x2][y2] = map[x2][y2][x1][y1] = z; } read(S); for(int i = 1; i <= S; ++i) { read(x1); read(y1); read(z); for(int j = 0; j < (1 << p); ++j) if (((1 << (z - 1)) & j) == 0) ins(j * n * m + (x1 - 1) * m + y1, (j | (1 << (z - 1))) * n * m + (x1 - 1) * m + y1, 0); } for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) for(int nu = 0; nu < 4; ++nu) { x1 = i + dx[nu]; y1 = j + dy[nu]; if (x1 > 0 && x1 <= n && y1 > 0 && y1 <= m) { if (map[i][j][x1][y1] == -1) { for(int l = 0; l < (1 << p); ++l) ins(l * n * m + (i - 1) * m + j, l * m * n + (x1 - 1) * m + y1, 1); } else if (map[i][j][x1][y1] > 0) { for(int l = 0; l < (1 << p); ++l) if ((1 << (map[i][j][x1][y1] - 1)) & l) ins(l * n * m + (i - 1) * m + j, l * n * m + (x1 -1) * m + y1, 1); } } } spfa(1); int Q = inf; for(int i = 0; i <= (1 << p); ++i) Q = min(Q, d[i * n * m]); printf("%d ", Q == inf ? -1 : Q); return 0; }
15.汽车加油形式问题 2016-04-18
还是最短路,,,BFS暴力过掉,不知道还有什么其他做法。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } struct node {int x, y, gas, cos;}; queue <node> q; int N, K, A, B, C, f[103][103][13], dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0}; short a[103][103]; int Q() { node u, now; memset(f, 127, sizeof(f)); f[1][1][K] = 0; u.x = u.y = 1; u.gas = K; u.cos = 0; q.push(u); while (!q.empty()) { u = q.front(); q.pop(); if (u.gas == 0) continue; for(int i = 0; i < 4; ++i) { now.x = u.x + dx[i]; now.y = u.y + dy[i]; if (now.x > 0 && now.x <= N && now.y > 0 && now.y <= N) { now.gas = u.gas - 1; now.cos = u.cos; if (now.x < u.x || now.y < u.y) now.cos += B; if (a[now.x][now.y]) { now.gas = K; now.cos += A; if (now.cos < f[now.x][now.y][now.gas]) f[now.x][now.y][now.gas] = now.cos, q.push(now); } else { if (now.cos < f[now.x][now.y][now.gas]) f[now.x][now.y][now.gas] = now.cos, q.push(now); now.gas = K; now.cos += A + C; if (now.cos < f[now.x][now.y][now.gas]) f[now.x][now.y][now.gas] = now.cos, q.push(now); } } } } int ret = 0x7fffffff; for(int i = 0; i <= K; ++i) ret = min(ret, f[N][N][i]); return ret; } int main() { read(N); read(K); read(A); read(B); read(C); for(int i = 1; i <= N; ++i) for(int j = 1; j <= N; ++j) read(a[i][j]); printf("%d ", Q()); return 0; }
16.数字梯形问题 2016-04-18
最小费用最大流,相当于写了3道水题,不过Ctrl+C,Ctrl+V大法好!建图时结点直接用坐标表示略偷懒
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], nxt[N], to[N], pre[N], from[N], cap[N], d[N], w[N], S, T, cnt = 1; bool spfa() { for(int i = 0; i <= T; ++i) vis[i] = 0, d[i] = inf; q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[T] != inf; } int mcmf() { int ret = 0, f, u; while (spfa()) { f = inf; for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += f * d[T]; } return ret; } int m, n, ss, nn, x[103][103]; void ins(int x, int y, int z, int zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } int main() { read(m); read(n); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m + i - 1; ++j) read(x[i][j]); nn = (m + n) * n; T = 2 * nn + 2; ss = T - 1; S = 0; ins(S, ss, m, 0); ins(ss, S, 0, 0); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m + i - 1; ++j) { ins((i - 1) * (n + m) + j, (i - 1) * (n + m) + j + nn, 1, - x[i][j]); ins((i - 1) * (n + m) + j + nn, (i - 1) * (n + m) + j, 0, x[i][j]); if (i == n) { ins((i - 1) * (n + m) + j + nn, T, 1, 0); ins(T, (i - 1) * (n + m) + j + nn, 0, 0); } else { if (i == 1) { ins(ss, (i - 1) * (n + m) + j, 1, 0); ins((i - 1) * (n + m) + j, ss, 0, 0); } ins((i - 1) * (n + m) + j + nn, i * (n + m) + j, 1, 0); ins(i * (n + m) + j, (i - 1) * (n + m) + j + nn, 0, 0); ins((i - 1) * (n + m) + j + nn, i * (n + m) + j + 1, 1, 0); ins(i * (n + m) + j + 1, (i - 1) * (n + m) + j + nn, 0, 0); } } int Q = mcmf(); printf("%d ", - Q); memset(point, 0, sizeof(point)); ins(S, ss, m, 0); ins(ss, S, 0, 0); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m + i - 1; ++j) { ins((i - 1) * (n + m) + j, (i - 1) * (n + m) + j + nn, inf, - x[i][j]); ins((i - 1) * (n + m) + j + nn, (i - 1) * (n + m) + j, 0, x[i][j]); if (i == n) { ins((i - 1) * (n + m) + j + nn, T, inf, 0); ins(T, (i - 1) * (n + m) + j + nn, 0, 0); } else { if (i == 1) { ins(ss, (i - 1) * (n + m) + j, 1, 0); ins((i - 1) * (n + m) + j, ss, 0, 0); } ins((i - 1) * (n + m) + j + nn, i * (n + m) + j, 1, 0); ins(i * (n + m) + j, (i - 1) * (n + m) + j + nn, 0, 0); ins((i - 1) * (n + m) + j + nn, i * (n + m) + j + 1, 1, 0); ins(i * (n + m) + j + 1, (i - 1) * (n + m) + j + nn, 0, 0); } } Q = mcmf(); printf("%d ", - Q); memset(point, 0, sizeof(point)); ins(S, ss, m, 0); ins(ss, S, 0, 0); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m + i - 1; ++j) { ins((i - 1) * (n + m) + j, (i - 1) * (n + m) + j + nn, inf, - x[i][j]); ins((i - 1) * (n + m) + j + nn, (i - 1) * (n + m) + j, 0, x[i][j]); if (i == n) { ins((i - 1) * (n + m) + j + nn, T, inf, 0); ins(T, (i - 1) * (n + m) + j + nn, 0, 0); } else { if (i == 1) { ins(ss, (i - 1) * (n + m) + j, 1, 0); ins((i - 1) * (n + m) + j, ss, 0, 0); } ins((i - 1) * (n + m) + j + nn, i * (n + m) + j, inf, 0); ins(i * (n + m) + j, (i - 1) * (n + m) + j + nn, 0, 0); ins((i - 1) * (n + m) + j + nn, i * (n + m) + j + 1, inf, 0); ins(i * (n + m) + j + 1, (i - 1) * (n + m) + j + nn, 0, 0); } } Q = mcmf(); printf("%d ", - Q); return 0; }
17.运输问题 2016-04-19
最小费用最大流,,,
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], nxt[N], cap[N], from[N], w[N], to[N], d[N], pre[N], S, T, cnt = 1; bool spfa() { for(int i = 1; i <= T; ++i) vis[i] = 0, d[i] = inf; q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[T] != inf; } int mcmf() { int ret = 0, f, u; while (spfa()) { f = inf; for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += f * d[T]; } return ret; } int m, n, x[503], c[503][503]; void ins(int x, int y, int z, int zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } int main() { read(m); read(n); S = 0; T = m + n + 1; for(int i = 1; i <= m; ++i) read(x[i]), ins(S, i, x[i], 0), ins(i, S, 0, 0); for(int i = m + 1; i < T; ++i) read(x[i]), ins(i, T, x[i], 0), ins(T, i, 0, 0); for(int i = 1; i <= m; ++i) for(int j = m + 1; j < T; ++j) { read(c[i][j]); ins(i, j, inf, c[i][j]); ins(j, i, 0, - c[i][j]); } int Q = mcmf(); printf("%d ", Q); memset(point, 0, sizeof(point)); cnt = 1; for(int i = 1; i <= m; ++i) ins(S, i, x[i], 0), ins(i, S, 0, 0); for(int i = m + 1; i < T; ++i) ins(i, T, x[i], 0), ins(T, i, 0, 0); for(int i = 1; i <= m; ++i) for(int j = m + 1; j < T; ++j) { ins(i, j, inf, - c[i][j]); ins(j, i, 0, c[i][j]); } Q = - mcmf(); printf("%d ", Q); return 0; }
18.分配问题 2016-04-19
最小费用最大流,,,,,,,,,,,,,,,,,
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], nxt[N], cap[N], from[N], w[N], to[N], d[N], pre[N], S, T, cnt = 1; bool spfa() { for(int i = 1; i <= T; ++i) vis[i] = 0, d[i] = inf; q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[T] != inf; } int mcmf() { int ret = 0, f, u; while (spfa()) { f = inf; for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += f * d[T]; } return ret; } int n, c[503][503]; void ins(int x, int y, int z, int zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } int main() { read(n); S = 0; T = n + n + 1; for(int i = 1; i <= n; ++i) ins(S, i, 1, 0), ins(i, S, 0, 0); for(int i = n + 1; i < T; ++i) ins(i, T, 1, 0), ins(T, i, 0, 0); for(int i = 1; i <= n; ++i) for(int j = n + 1; j < T; ++j) { read(c[i][j]); ins(i, j, inf, c[i][j]); ins(j, i, 0, - c[i][j]); } int Q = mcmf(); printf("%d ", Q); memset(point, 0, sizeof(point)); cnt = 1; for(int i = 1; i <= n; ++i) ins(S, i, 1, 0), ins(i, S, 0, 0); for(int i = n + 1; i < T; ++i) ins(i, T, 1, 0), ins(T, i, 0, 0); for(int i = 1; i <= n; ++i) for(int j = n + 1; j < T; ++j) { ins(i, j, inf, - c[i][j]); ins(j, i, 0, c[i][j]); } Q = - mcmf(); printf("%d ", Q); return 0; }
19.负载平衡问题 2016-04-19
还是最小费用最大流,我第一次WA了,因为只是将$X_i$连了一条向$Y_i$的流量无穷大的边,但有可能出现一些货物运输跨过几个仓库的情况,于是便从$Y_i$向$X_i$连一流量无穷大的边,保证货物在运输一次之后可以继续运输。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 10003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], nxt[N], from[N], to[N], pre[N], cap[N], w[N], d[N], S, T, cnt = 1; bool spfa() { for(int i = 1; i <= T; ++i) vis[i] = 0, d[i] = inf; q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[T] != inf; } int mcmf() { int ret = 0, f, u; while (spfa()) { f = inf; for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += f * d[T]; } return ret; } int n, x, Qsum = 0, to1, to2; void ins(int x, int y, int z, int zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } int main() { read(n); S = 0; T = (n << 1) + 1; for(int i = 1; i <= n; ++i) read(x), ins(S, i, x, 0), ins(i, S, 0, 0), Qsum += x; for(int i = n + 1; i < T; ++i) ins(i, T, Qsum / n, 0), ins(T, i, 0, 0); for(int i = 1; i <= n; ++i) { ins(i, i + n, inf / 2, 0); ins(i + n, i, inf / 2, 0); to1 = i == 1 ? n + n : i - 1 + n; to2 = i == n ? 1 + n : i + 1 + n; ins(i, to1, inf, 1); ins(to1, i, 0, -1); ins(i, to2, inf, 1); ins(to2, i, 0, -1); } int Q = mcmf(); printf("%d ", Q); return 0; }
20.深海机器人问题 2016-04-19
BYVoid的题解上说是线性规划网络优化,可是我并没有看出来线性规划用在哪里了,,,这道题建图时因为一条道路上的生物只能采集一次,所以得设流量限制为1,但因为在这条路上采集后其他机器人还可以再走,所以再连一条容量为无穷,费用为0的边,保证了后来的任何机器人都可以从这条路上走过而且不会计算费用233。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], from[N], nxt[N], to[N], cap[N], d[N], pre[N], w[N], S, T, cnt = 1; bool spfa() { for(int i = 0; i <= T; ++i) vis[i] = 0, d[i] = inf; q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[T] != inf; } int mcmf() { int ret = 0, f, u; while (spfa()) { f = inf; for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += d[T] * f; } return ret; } int P, Q, a, b, r, x, y; void ins(int x, int y, int z, int zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } int main() { read(a); read(b); read(P); read(Q); S = (P + 1) * (Q + 1) + 1; T = S + 1; for(int i = 0; i <= P; ++i) for(int j = 0; j < Q; ++j) { read(x); ins(i * (Q + 1) + j, i * (Q + 1) + j + 1, 1, - x); ins(i * (Q + 1) + j + 1, i * (Q + 1) + j, 0, x); ins(i * (Q + 1) + j, i * (Q + 1) + j + 1, inf, 0); ins(i * (Q + 1) + j + 1, i * (Q + 1) + j, 0, 0); } for(int j = 0; j <= Q; ++j) for(int i = 0; i < P; ++i) { read(x); ins(i * (Q + 1) + j, (i + 1) * (Q + 1) + j, 1, - x); ins((i + 1) * (Q + 1) + j, i * (Q + 1) + j, 0, x); ins(i * (Q + 1) + j, (i + 1) * (Q + 1) + j, inf, 0); ins((i + 1) * (Q + 1) + j, i * (Q + 1) + j, 0, 0); } for(int i = 1; i <= a; ++i) { read(r); read(x); read(y); ins(S, x * (Q + 1) + y, r, 0); ins(x * (Q + 1) + y, S, 0, 0); } for(int i = 1; i <= b; ++i) { read(r); read(x); read(y); ins(x * (Q + 1) + y, T, r, 0); ins(T, x * (Q + 1) + y, 0, 0); } int QQ = - mcmf(); printf("%d ", QQ); return 0; }
21.最长k可重区间集问题 2016-04-19
查了3h错,因为离散化完全写错了,还有这道题数据辣么水,为什么要写离散化(┙>∧<)┙へ┻┻。重写了离散化之后还是WA三个点,又查了1h+后在codevs的题解上发现数据错了(゚皿゚メ)
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 100003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], from[N], nxt[N], to[N], cap[N], w[N], d[N], pre[N], S, T, cnt = 1; bool spfa() { for(int i = 1; i <= T; ++i) vis[i] = 0, d[i] = inf; q.push(S); vis[S] = 0; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[T] != inf; } int mcmf() { int ret = 0, f, u; while (spfa()) { f = inf; for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += f * d[T]; } return ret; } struct node { int l, r; } a[1003]; int n, k, H[2003], id[2003], HH[2003], num = 1, cos, He[2003]; bool cmp2(int X, int Y) {return H[X] < H[Y];} void ins(int x, int y, int z, int zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } int main() { read(n); read(k); for(int i = 1; i <= n; ++i) read(H[(i << 1) - 1]), read(H[i << 1]); for(int i = 1; i <= (n << 1); ++i) id[i] = i; sort(id + 1, id + (n << 1) + 1, cmp2); for(int i = 1; i <= (n << 1); ++i) { He[num] = H[id[i]]; HH[id[i]] = num; if (H[id[i]] != H[id[i + 1]] && i != (n << 1)) ++num; } S = 0; T = num + 1; ins(S, 1, k, 0); ins(1, S, 0, 0); ins(num, T, k, 0); ins(T, num, 0, 0); for(int i = 1; i < num; ++i) ins(i, i + 1, inf, 0), ins(i + 1, i, 0, 0); for(int i = 1; i < (n << 1); i += 2) { cos = He[HH[i + 1]] - He[HH[i]]; ins(HH[i], HH[i + 1], 1, - cos); ins(HH[i + 1], H[i], 0, cos); printf("%d %d : %d ", HH[i], HH[i + 1], cos); } int Q = - mcmf(); printf("%d ", Q); return 0; }
22.最长k可重线段集问题 2016-04-19
查错查了一个下午,发现各大OJ上此题AC率都是0,最后Menci神犇说数据有误,,,不管对不对,我还是先把自己愚蠢的代码贴上来吧
#include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const long long N = 1000003; const long long inf = 0x7fffffff; long long getint() { long long k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <long long> q; bool vis[N]; long long point[N], from[N], nxt[N], to[N], cap[N], d[N], w[N], pre[N], S, T, cnt = 1; bool spfa() { for(long long i = 0; i <= T; ++i) vis[i] = 0, d[i] = inf; q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { long long u = q.front(); q.pop(); vis[u] = 0; for(long long i = point[u]; i; i = nxt[i]) if (cap[i] && d[to[i]] > d[u] + w[i]) { d[to[i]] = d[u] + w[i]; pre[to[i]] = i; if (!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } return d[T] != inf; } long long mcmf() { long long ret = 0, f, u; while (spfa()) { f = inf; for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]); for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f; ret += d[T] * f; } return ret; } long long n, k, num = 1, W[1003], H[2003], id[2003], HH[2003]; void ins(long long x, long long y, long long z, long long zz) { nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt; } long long sqr(long long x) {return x * x;} bool cmp(long long X, long long Y) {return H[X] < H[Y];} int main() { long long x1, x2, y1, y2; read(n); read(k); for(long long i = 1; i <= n; ++i) { read(x1); read(y1); read(x2); read(y2); if (x1 > x2) swap(x1, x2), swap(y1, y2); H[(i << 1) - 1] = x1; H[i << 1] = x2; W[i] = floor(sqrt(sqr(x1 - x2) + sqr(y1 - y2))); } for(long long i = 1; i <= (n << 1); ++i) id[i] = i; sort(id + 1, id + (n << 1) + 1, cmp); for(long long i = 1; i <= (n << 1); ++i) { HH[id[i]] = num; if (H[id[i]] != H[id[i + 1]] && i != (n << 1)) ++num; } S = 0; T = (num << 1) + 1; ins(S, 1, k, 0); ins(1, S, 0, 0); ins(num << 1, T, k, 0); ins(T, num << 1, 0, 0); for(long long i = 1; i < (num << 1); ++i) ins(i, i + 1, inf, 0), ins(i + 1, i, 0, 0); for(long long i = 1; i <= n; ++i) { long long le = HH[(i << 1) - 1], ri = HH[i << 1]; if (le == ri) { ins((le << 1) - 1, le << 1, 1, - W[i]); ins(le << 1, (le << 1) - 1, 0, W[i]); } else { ins(le << 1, (ri << 1) - 1, 1, - W[i]); ins((ri << 1) - 1, le << 1, 0, W[i]); } } long long Q = - mcmf(); printf("%d ", Q); return 0; }
23.火星探险问题 2016-04-19
数据还是有问题!!!和深海机器人问题差不多,我就不做了吧,,,毕竟A不了
24.骑士共存问题 2016-04-19
典型最大权闭合图,染色后建图,,,zyf神犇说这是道水题←此话没有特别意思
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int N = 1000003; const int inf = 0x7fffffff; int getint() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh; } queue <int> q; bool vis[N]; int point[N], cur[N], d[N], cap[N], nxt[N], to[N], S, T, cnt = 1; bool BFS() { memset(vis, 0, sizeof(vis)); q.push(S); vis[S] = 1; d[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for(int i = point[u]; i; i = nxt[i]) if (!vis[to[i]] && cap[i]) { d[to[i]] = d[u] + 1; vis[to[i]] = 1; q.push(to[i]); } } return vis[T]; } int DFS(int u, int a) { if (u == T || !a) return a; int flow = 0, f; for(int &i = cur[u]; i; i = nxt[i]) if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) { flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f; if (!a) break; } return flow; } int Dinic() { int flow = 0, i; while (BFS()) { for(i = 0; i <= T; ++i) cur[i] = point[i]; flow += DFS(S, inf); } return flow; } bool pd[203][203]; int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}, dy[8] = {2, 1, -1, -2, -2, -1, 1, 2}; int n, m, x, y; void ins(int x, int y, int z) { nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt; } int main() { read(n); read(m); for(int i = 1; i <= m; ++i) { read(x); read(y); pd[x][y] = 1; } S = 0; T = n * n + 1; for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) if (!pd[i][j]) if ((i + j) % 2 ==0) { ins(S, (i - 1) * n + j, 1); ins((i - 1) * n + j, S, 0); } else { ins((i - 1) * n + j, T, 1); ins(T, (i - 1) * n + j, 0); } for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) if (!pd[i][j] && (i + j) % 2 == 0) for(int k = 0; k < 8; ++k) { x = i + dx[k]; y = j + dy[k]; if (x < 1 || x > n || y < 1 || y > n || pd[x][y]) continue; int now = (x - 1) * n + y; ins((i - 1) * n + j, now, inf); ins(now, (i - 1) * n + j, 0); } int Q = Dinic(); printf("%d ", n * n - m - Q); return 0; }
2016-04-19:线性规划与网络流24题就告一段落了,因为8机器人路径规划问题有点困难,暂时先放一放,还有最长k可重线段集问题和火星探险问题2道题的测试数据存在较大问题,没有办法AC,所以那三道题就先被我抛弃了QAQ。说好的线性规划呢?做完了连线性规划的影子都没见到,还是我太弱根本不懂线性规划QuQ。今天是停课第二天,我有没有取得进步自己也说不清楚,走一步看一步吧。CTSC2016, SDOI2016 Round2 Bless All!