JZOJ 5640 劈配

xiaoxiao2021-02-28  25

传送门考场上的思路失误卡常参考代码

传送门
考场上的思路

  很明显需要二分图。发现第一问可以一个一个贪心处理,每次动态加边跑网络流。

  第二问的话,发现可以利用第一问的答案,对于一个人 i i ,他之前的所有人的档次一定是第一问的答案。所以可以枚举答案,对于前面的人只加上他第一问的答案对应的边,这也正好说明了为什么对 cc 有限制。

  本来以为稳了,不说 100 100 ,至少 80 80 分还是有的,于是我就期望得分 100 100 ,结果一下来, 40 40 什么鬼??!

失误

  这里详细说一下第二问我是怎么做的。对于第 i i 个人,我先把他档次小于等于 sisi 的边加入到图中,然后跑最大流。如果没有流,说明这个人没有理想,答案为 i i ,否则我们从 11 开始枚举到 i1 i − 1

  对于枚举到的人 j j ,把他的档次为他第一问的答案的边加进图中跑最大流,如果能够增广,说明从 11 i i 增广也能增广;如果不能增广,说明从 11 i i 增广也不能增广(即:存在矛盾)。这时我就退出。

  问题就出在上面这里。我忘记了如果第一问答案为 m 1m 1 要直接跳过……

卡常

  结果还是被卡成了 90 90 分。

  可能我的时间复杂度不对吧,但我感觉挺对的……仔细观察,发现根本不需要 Dinic,因为一次最多只能找到一条增广路,干嘛要打多路增广呢?直接 Edmonds-Karp 单路增广就好了。在氧气的环绕下,发现 Dinic 并不比 Edmonds-Karp 慢,换成了 EK 还是超时。

  然后我把队列换成手写的了,然后就卡过了……

  另外中途我尝试把 vector 换成数组,结果慢了一倍。得出结论:当开 O2 优化时,vector 很快,不开 O2 优化时 vector 很慢,数组稍微好一点。queue 由于其实现的问题,常数很大,建议手写(毕竟 BFS 时元素总量是确定的)。

参考代码
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <cassert> #include <cctype> #include <climits> #include <ctime> #include <iostream> #include <algorithm> #include <vector> #include <string> #include <stack> #include <queue> #include <deque> #include <map> #include <set> #include <bitset> #include <list> #include <functional> typedef long long LL; typedef unsigned long long ULL; using std::cin; using std::cout; using std::endl; typedef int INT_PUT; INT_PUT readIn() { INT_PUT a = 0; bool positive = true; char ch = getchar(); while (!(ch == '-' || std::isdigit(ch))) ch = getchar(); if (ch == '-') { positive = false; ch = getchar(); } while (std::isdigit(ch)) { (a *= 10) -= ch - '0'; ch = getchar(); } return positive ? -a : a; } void printOut(INT_PUT x) { char buffer[20]; int length = 0; if (x < 0) putchar('-'); else x = -x; do buffer[length++] = -(x % 10) + '0'; while (x /= 10); do putchar(buffer[--length]); while (length); putchar(' '); } const int INF = (~(int(1) << (sizeof(int) * 8 - 1))) >> 1; const int maxn = 205; int T, C; int n, m; int b[maxn]; int rect[maxn][maxn]; std::vector<std::vector<int> > teacher[maxn]; int s[maxn]; struct NetworkFlow { struct Edge { int from, to, cap, flow; Edge() {} Edge(int from, int to, int cap) : from(from), to(to), cap(cap), flow() {} }; std::vector<Edge> edges; std::vector<std::vector<int> > G; int s, t; void addEdge(int from, int to, int cap) { edges.push_back(Edge(from, to, cap)); edges.push_back(Edge(to, from, 0)); int i = edges.size(); G[from].push_back(i - 2); G[to].push_back(i - 1); } std::vector<int> vis; std::vector<int> opt; std::vector<int> pre; bool BFS(int& flow) { static int stamp; stamp++; static int q[maxn * 2]; int head = 0, tail = 0; q[tail++] = s; vis[s] = stamp; opt.clear(); opt.resize(n + m + 2, 0); pre.resize(n + m + 2); opt[s] = INF; while (head != tail) { int from = q[head++]; for (int i = 0; i < G[from].size(); i++) { const Edge& e = edges[G[from][i]]; if (e.flow < e.cap && vis[e.to] != stamp) { opt[e.to] = std::min(opt[from], e.cap - e.flow); pre[e.to] = G[from][i]; vis[e.to] = stamp; q[tail++] = e.to; if (vis[t] == stamp) break; } } } if (vis[t] != stamp) return false; flow += opt[t]; for (int u = t; u != s; u = edges[pre[u]].from) { edges[pre[u]].flow += opt[t]; edges[pre[u] ^ 1].flow -= opt[t]; } return true; } int EdmondsKarp() { int flow = 0; while (BFS(flow)); return flow; } void clear(int newSize) { edges.clear(); edges.reserve(n * m * 10); G.clear(); G.resize(newSize); vis.resize(newSize); } } nf; #define RunInstance(x) delete new x struct cheat { cheat() { int lastSel = 0; int remain = b[1]; for (int i = 1; i <= n; i++) if (rect[i][1] == 1) { if (remain) { printOut(1); lastSel = i; remain--; } else printOut(m + 1); } else printOut(m + 1); putchar('\n'); for (int i = 1; i <= n; i++) if (rect[i][1] == 1) printOut(std::max(0, i - lastSel)); else printOut(i); } }; struct work { int ans1[maxn]; int ans2[maxn]; work() : ans1(), ans2() { nf.clear(n + m + 2); nf.s = 0; nf.t = n + m + 1; for (int i = 1; i <= n; i++) nf.addEdge(nf.s, i, 1); for (int i = 1; i <= m; i++) nf.addEdge(n + i, nf.t, b[i]); for (int i = 1; i <= n; i++) { int& j = ans1[i]; for (j = 1; j <= m; j++) { for (int k = 0; k < teacher[i][j].size(); k++) nf.addEdge(i, n + teacher[i][j][k], 1); if (nf.EdmondsKarp()) break; } } for (int i = 1; i <= n; i++) { if (ans1[i] <= s[i]) { ans2[i] = 0; continue; } nf.clear(n + m + 2); for (int j = 1; j <= n; j++) nf.addEdge(nf.s, j, 1); for (int j = 1; j <= m; j++) nf.addEdge(n + j, nf.t, b[j]); for (int j = 1; j <= s[i]; j++) for (int k = 0; k < teacher[i][j].size(); k++) nf.addEdge(i, n + teacher[i][j][k], 1); if (!nf.EdmondsKarp()) { ans2[i] = i; continue; } int& j = ans2[i]; for (j = 1; j < i; j++) // try to be the j + 1(th) { if (ans1[j] == m + 1) continue; const std::vector<int> Teacher = teacher[j][ans1[j]]; for (int k = 0; k < Teacher.size(); k++) nf.addEdge(j, n + Teacher[k], 1); int aug = nf.EdmondsKarp(); if (!aug) break; // fail to be the j + 1(th), be the j(th) } j = i - j; } for (int i = 1; i <= n; i++) printOut(ans1[i]); putchar('\n'); for (int i = 1; i <= n; i++) printOut(ans2[i]); } }; void run() { T = readIn(); C = readIn(); while (T--) { n = readIn(); m = readIn(); for (int i = 1; i <= m; i++) b[i] = readIn(); for (int i = 1; i <= n; i++) { teacher[i].clear(); teacher[i].resize(m + 1); for (int j = 1; j <= m; j++) if (rect[i][j] = readIn()) teacher[i][rect[i][j]].push_back(j); } for (int i = 1; i <= n; i++) s[i] = readIn(); if (m == 1) RunInstance(cheat); else RunInstance(work); putchar('\n'); } } int main() { #ifndef LOCAL freopen("mentor.in", "r", stdin); freopen("mentor.out", "w", stdout); #endif run(); return 0; }
转载请注明原文地址: https://www.6miu.com/read-2627869.html

最新回复(0)