XVI Open Cup named after E.V. Pankratiev. GP of Eurasia
C.Inequalities
给你若干二元不等式,求一组合法解
差分约束系统,使用最长路求解,需要用spfa看图里是否存在正权环,如果存在就无解
#include <bits/stdc++.h> using namespace std; #define rep(i, j, k) for (int i = int(j); i <= int(k); ++ i) const int N = 1e5 + 7; typedef pair<int, int> P; const int inf = 2e9; int n, k, d[N], maxv[N], cnt[N], inq[N], q[N]; inline int readint() { char c = getchar(); while (c == '\n' || c == ' ') c = getchar(); int op = 1, x = 0; if (c == '-') op = -1, c = getchar(); while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * op; } int ehead[N], tot = 0; struct edge { int v, cost, next; }e[N << 2]; int main() { scanf("%d%d", &n, &k); rep(i, 0, k) d[i] = -inf, maxv[i] = inf; bool ok = 1; auto add = [&](int u, int v, int w) { ++ tot; e[tot].next = ehead[u]; e[tot].v = v; e[tot].cost = w; ehead[u] = tot; }; rep(i, 1, n) { int op, t1, x1, t2, x2; op = readint(); t1 = readint(); x1 = readint(); t2 = readint(); x2 = readint(); if (t1 == 0 && t2 == 0) { // v[x1] + op <= v[x2] add(x1, x2, op); } else if (t1 == 0 && t2 == 1) { // v[x1] + op <= x2 maxv[x1] = min(maxv[x1], x2 - op); } else if (t1 == 1 && t2 == 0) { // x1 + op <= v[x2] d[x2] = max(d[x2], x1 + op); } else { // x1 + op <= x2 if (x1 + op > x2) ok = 0; } } if (!ok) { printf("NO\n"); return 0; } int head = 0, tail = 0; auto push_back = [&](int x) { q[tail ++] = x; if (tail == N) tail = 0; }; auto push_front = [&](int x) { if (head == 0) head = N - 1; else head --; q[head] = x; }; auto pop = [&]() -> int { int t = q[head]; head ++; if (head == N) head = 0; return t; }; rep(i, 1, k) inq[i] = 1, push_back(i); auto spfa = [&]() -> bool { while (head != tail) { int u = pop(); inq[u] = 0; for (int i = ehead[u]; i; i = e[i].next) { int v = e[i].v; if (d[v] < d[u] + e[i].cost) { d[v] = d[u] + e[i].cost; if (d[v] > maxv[v]) return 0; if (!inq[v]) { inq[v] = 1; cnt[v] ++; if (cnt[v] >= n) return 0; // if (e[i].cost == 0) push_front(v); // else push_back(v); push_front(v); } } } } return 1; }; bool flag = spfa(); if (!flag) { printf("NO\n"); return 0; } printf("YES\n"); rep(i, 1, k) printf("%d\n", d[i]); } /* 2 2 1 0 1 0 2 0 0 2 0 1 3 2 1 0 1 0 2 0 1 5 0 1 0 0 2 1 7 */
J.Civilization
细节很多的网络流,注意到城市很少,只需要枚举哪些城市一定被打了
#include <bits/stdc++.h> using namespace std; #define rep(i, j, k) for (int i = int(j); i <= int(k); ++ i) #define dwn(i, j, k) for (int i = int(j); i >= int(k); -- i) typedef long long LL; typedef pair<int, int> P; typedef vector<int> VI; typedef vector<P> VII; const int MaxNode = 10000; const int MaxEdge = 100000; const int INF = 1e9; int n, m, C, H, W; struct Civi{ int x, y, p; void read2() { scanf("%d%d", &x, &y); } void read3() { scanf("%d%d%d", &x, &y, &p); } }city[10], cata[110], mount[1010]; int g[10]; // 连着T的城市的边的的编号 int cnt = 0; map<P, int> mp; bool ban[MaxNode], can[MaxNode]; P pos[MaxNode]; int getX(int x, int y) { // 离散化平面上的点 if (mp.count(P(x, y))) return mp[P(x, y)]; pos[++cnt] = P(x, y); return mp[P(x, y)] = cnt; } int vis1[MaxNode][10], vis2[MaxNode], dx[6] = {0, 1, 1, 0, -1, -1}, dy[6] = {1, 0, -1, -1, 0, 1}; struct Network { int n, etot = 1; int d[MaxNode]; // 层次图标号 int head[MaxNode]; int cur[MaxNode]; struct Edge { int to, next, cap; }e[MaxEdge], e2[MaxEdge]; void add(int u, int v, int w) { etot ++; e[etot].to = v; e[etot].next = head[u]; e[etot].cap = w; head[u] = etot; etot ++; e[etot].to = u; e[etot].next = head[v]; e[etot].cap = 0; head[v] = etot; } bool bfs(int src, int dest) { rep(i, 0, n) d[i] = 0; d[src] = 1; cur[src] = head[src]; queue<int> Q; Q.push(src); while (!Q.empty()) { int r = Q.front(); Q.pop(); for (int i = head[r]; i; i = e[i].next) { int v = e[i].to; if (e[i].cap && !d[v]) { d[v] = d[r] + 1; cur[v] = head[v]; Q.push(v); } } } return d[dest]; } int dfs(int u, int dest, int a) { if (u == dest || !a) return a; int flow = 0, f, v; for (int &i = cur[u]; i; i = e[i].next) { v = e[i].to; if (d[v] == d[u] + 1 && (f = dfs(v, dest, min(a, e[i].cap) ) ) > 0) { e[i].cap -= f; e[i ^ 1].cap += f; a -= f; flow += f; if (!a) break; } } return flow; } int dinic(int src, int dest) { int flow = 0; while (bfs(src, dest)) flow += dfs(src, dest, INF); return flow; } void solve(int S, int T, int n, int cityNum, int cataNum) { this -> n = n; rep(i, 2, etot) e2[i] = e[i]; static int mask[20], maskSize[20]; rep(i, 1, (1 << cityNum) - 1) mask[i] = i, maskSize[i] = maskSize[i ^ (i & -i)] + 1; sort(mask, mask + (1 << cityNum), [&](int i, int j){ return maskSize[i] > maskSize[j]; }); int ansMask = -1; for (int i = 0; i < (1 << n); ++ i) { int cityMask = mask[i]; rep(j, 2, etot) e[j] = e2[j]; int flow = 0; rep(j, 1, cityNum) if (((cityMask >> (j - 1)) & 1) == 0) e[g[j]].cap = 0; else flow += e[g[j]].cap; // cout << "??\n"; if (dinic(S, T) == flow) { ansMask = cityMask; break; } } printf("%d\n", maskSize[ansMask]); static int m1[MaxNode], m2[MaxNode]; for (int i = 2; i <= etot; i += 2) { int from = e[i ^ 1].to, to = e[i].to; if (e[i].cap) continue; if (from >= 1 + cityNum && from <= cityNum + cataNum) m1[from - cityNum] = (to - cityNum - cataNum + 1) / 2; if (to >= 1 && to <= cityNum) m2[(from - cityNum - cataNum + 1) / 2] = to; } // 防止一个炮车不移动,另外一个炮车挪动到这个位置后位置冲突 for (;;) { bool flag = 1; for (int i = 1; i <= cataNum && flag; ++ i) { if (!m1[i]) for (int j = 1; j <= cataNum && flag; ++ j) if (m1[j] && m1[j] == getX(cata[i].x, cata[i].y)) { flag = 0; m1[i] = m1[j]; m1[j] = 0; } } if (flag) break; } rep(i, 1, cataNum) { if (!m1[i]) printf("%d %d %d\n", cata[i].x, cata[i].y, 0); else printf("%d %d %d\n", pos[m1[i]].first, pos[m1[i]].second, m2[m1[i]]); } } }net; void dfs(int x, int y, int d, int col, int op) { // op = 0 -- if (x < 0 || x >= W || y < 0 || y >= H) return; int u = getX(x, y); if (vis1[u][d] == col) return; vis1[u][d] = col; if (op && ban[u]) return; if (vis2[u] != col) { // 判断这个点是否被搜素过 // if (col == 3) cout << x << ' ' << y << '\n'; if (op == 0) { net.add(n + m + 2 * u, col, 1); can[u] = 1; } else if (can[u]) net.add(col, n + m + 2 * u - 1, 1); // 只有当这个点可以攻击到目标点,才加边 vis2[u] = col; } if (!d) return; rep(i, 0, 5) dfs(x + dx[i], y + dy[i], d - 1, col, op); } int main() { scanf("%d%d", &W, &H); scanf("%d", &n); rep(i, 1, n) city[i].read3(), ban[getX(city[i].x, city[i].y)] = 1; scanf("%d", &m); rep(i, 1, m) cata[i].read3(); scanf("%d", &C); rep(i, 1, C) mount[i].read2(), ban[getX(mount[i].x, mount[i].y)] = 1; rep(i, 1, n) dfs(city[i].x, city[i].y, 2, i, 0); rep(i, 1, m) dfs(cata[i].x, cata[i].y, cata[i].p - 1, n + i, 1); int S = n + m + 2 * cnt + 1, T = S + 1; rep(i, 1, m) net.add(S, i + n, 1); // 每个炮车最多打一个城市 rep(i, 1, n) net.add(i, T, city[i].p), g[i] = net.etot - 1; // 每个城市有city[i].p的血 rep(i, 1, cnt) net.add(n + m + 2 * i - 1, n + m + 2 * i, 1); // 每个位置最多停一辆炮车 net.solve(S, T, T, n, m); } /* 10 3 2 3 1 2 9 1 1 3 1 1 1 6 1 2 7 0 3 3 2 1 7 1 8 0 */