骑士共存问题
按马的轨迹连边,最后是一张二分图,求最大匹配。可以跑匈牙利直接求出来,也可以连源点和汇点跑Dinic。
我是学二分图的时候写的,当时写的是匈牙利。我当时码风好奇怪
1 #include <bits/stdc++.h> 2 #define ID(x, y) (x - 1) * n + y 3 #define New(p) p = &tmp[++ecnt] 4 5 struct Edge {int to; Edge *nxt;} tmp[1000005], *head[40005]; 6 7 int vis[40005], match[40005], ecnt = -1, n, m, tim, ans, tot; 8 int dx[] = {-1, -2, 1, 2, -1, -2, 1, 2}, dy[]={-2, -1, -2, -1, 2, 1, 2, 1}; 9 bool ban[205][205]; 10 11 inline void Add(int f, int to) {Edge *p; New(p); p -> to = to, p -> nxt = head[f], head[f] = p;} 12 13 bool dfs(int x) { 14 for (Edge *i = head[x]; i != NULL; i = i -> nxt) { 15 if (vis[i -> to] != tim) { 16 vis[i -> to] = tim; 17 if (!match[i -> to] || dfs(match[i -> to])) { 18 match[i -> to] = x; 19 return 1; 20 } 21 } 22 } 23 return 0; 24 } 25 26 signed main() { 27 scanf("%d%d", &n, &m); 28 for (int i = 1, x, y; i <= m; i++) { 29 scanf("%d%d", &x, &y); 30 ban[x][y] = 1; 31 } 32 for (int i = 1; i <= n; i++) { 33 for (int j = 1; j <= n; j++) { 34 if(ban[i][j] || ((i + j) & 1)) continue; 35 for (int k = 0; k < 8; k++) { 36 int x = i + dx[k], y = j + dy[k]; 37 if (ban[x][y] || x < 1 || x > n || y < 1 || y > n) continue; 38 Add(ID(i, j), ID(x, y)); 39 } 40 } 41 } 42 for (int i = 1; i <= n; i++) { 43 for (int j = 1; j <= n; j++) { 44 if (!ban[i][j]) { 45 ++tim; 46 ++tot; 47 if (dfs(ID(i, j))) ++ans; 48 } 49 } 50 } 51 printf("%d ", tot - ans); 52 return 0; 53 }
飞行员配对方案问题
按给定关系建图,仍是二分图,求最大匹配。
依旧写的是匈牙利。我当时没看见SPJ,写了一堆奇怪的东西。。。。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 1005 4 5 namespace Gekoo { 6 struct Edge { 7 int to, nxt; 8 }e[N]; 9 10 pair<int, int> p[N]; 11 12 int m, n, head[N], ecnt, match[N], ans, pcnt; 13 bool vis[N]; 14 15 void AddEdge(int f, int to) { 16 e[++ecnt].to = to; 17 e[ecnt].nxt = head[f]; 18 head[f] = ecnt; 19 } 20 21 bool dfs(int u) { 22 for (int i = head[u]; i; i = e[i].nxt) { 23 int v = e[i].to; 24 if (!vis[v]) { 25 vis[v] = 1; 26 if (!match[v] || dfs(match[v])) { 27 match[v] = u; 28 return 1; 29 } 30 } 31 } 32 return 0; 33 } 34 35 void QAQ() { 36 scanf("%d%d", &m, &n); 37 int i, j; 38 while (1) { 39 scanf("%d%d", &i, &j); 40 if (i == -1 && j == -1) break; 41 else AddEdge(i, j); 42 } 43 for (int i = 1; i <= m; i++) { 44 memset(vis, 0, sizeof(vis)); 45 if(dfs(i)) ans++; 46 } 47 if (ans == 0) { 48 puts("No Solution!"); 49 return ; 50 } else { 51 printf("%d ", ans); 52 for (int i = m + 1; i <= n; i++) { 53 if (match[i]) { 54 p[++pcnt] = make_pair(match[i], i); 55 } 56 } 57 sort(p + 1, p + 1 + pcnt); 58 for (int i = 1; i <= pcnt; i++) { 59 printf("%d %d ", p[i].first, p[i].second); 60 } 61 return ; 62 } 63 } 64 } 65 66 signed main() { 67 Gekoo::QAQ(); 68 return 0; 69 }
方格取数问题
把图按格子奇偶性黑白染色,源点连黑色,白色连汇点,黑色向相邻白点连,求出最小割,用数字和减去。
建出来的仍是二分图,这个过程其实就是在求二分图的最大独立集。
1 #include <bits/stdc++.h> 2 #define id(x, y) ((x - 1) * m + y) 3 4 const int N = 500005, INF = 0x3f3f3f3f; 5 const int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1}; 6 int n, m, sum, ecnt = 1, S, T; 7 int matrix[105][105], head[N], dep[N]; 8 struct Edge { 9 int to, nxt, val; 10 } e[N << 5]; 11 12 inline void addEdge(int f, int to, int val) { 13 e[++ecnt] = {to, head[f], val}, head[f] = ecnt; 14 e[++ecnt] = {f, head[to], 0}, head[to] = ecnt; 15 } 16 17 bool bfs() { 18 memset(dep, 0, sizeof(dep)); 19 dep[S] = 1; 20 std::queue<int> q; 21 q.push(S); 22 while (!q.empty()) { 23 int x = q.front(); 24 q.pop(); 25 for (int i = head[x], y = e[i].to; i; i = e[i].nxt, y = e[i].to) { 26 if (!dep[y] && e[i].val) { 27 dep[y] = dep[x] + 1; 28 if (y == T) return true; 29 q.push(y); 30 } 31 } 32 } 33 return false; 34 } 35 36 int dfs(int x, int flow) { 37 if (x == T) return flow; 38 int las = flow, q; 39 for (int i = head[x], y = e[i].to; i; i = e[i].nxt, y = e[i].to) { 40 if (dep[y] == dep[x] + 1 && e[i].val && las) { 41 q = dfs(y, std::min(e[i].val, las)); 42 if (!q) {dep[y] = 0; continue;} 43 las -= q, e[i].val -= q, e[i^1].val += q; 44 } 45 } 46 return flow - las; 47 } 48 49 int dinic() { 50 int maxflow = 0; 51 while (bfs()) maxflow += dfs(S, INF); 52 return maxflow; 53 } 54 55 signed main() { 56 scanf("%d%d", &n, &m); 57 for (int i = 1; i <= n; i++) { 58 for (int j = 1; j <= m; j++) { 59 scanf("%d", &matrix[i][j]); 60 sum += matrix[i][j]; 61 } 62 } 63 S = n * m + 1, T = S + 1; 64 for (int i = 1; i <= n; i++) { 65 for (int j = 1; j <= m; j++) { 66 if ((i + j) & 1) { 67 addEdge(S, id(i, j), matrix[i][j]); 68 for (int k = 0; k <= 3; k++) { 69 int xx = i + dx[k], yy = j + dy[k]; 70 if (xx < 1 || yy < 1 || xx > n || yy > m) continue; 71 addEdge(id(i, j), id(xx, yy), INF); 72 } 73 } else { 74 addEdge(id(i, j), T, matrix[i][j]); 75 } 76 } 77 } 78 printf("%d ", sum - dinic()); 79 return 0; 80 }