经出题人同意,决定把此次比赛的题解放在此处供大家参考,如果有纰漏请及时反馈!
1212 刺激战场
题目:http://acm.guet.edu.cn/problem/view/1212.html
思路:
建立二分图:左半部分代表每行,右半部分代表每列。而行顶点i和列顶点j之间的连线就代表图 (i, j) 处有一个玩家。例如对于输入范例可建立以下二分图:
要求最少操作次数即求该二分图的最小点覆盖集,也就是最大匹配。这里使用了dinic算法求最大匹配,即先将二分图转化为网络流,再进行计算。
#include <bits/stdc++.h> using namespace std; const int kMax = 20000 + 10; const int kInf = 1e9; struct node { int v, cost; node(int _v, int _cost) : v(_v), cost(_cost) {} }; int s, t, n; int d[kMax]; vector<node> table[kMax]; bool bfs() { memset(d, -1, sizeof(d)); queue<int> q; q.push(s); d[s] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = 0;i < table[u].size();++ i) { int v = table[u][i].v; if (table[u][i].cost > 0 && d[v] == -1) { q.push(v); d[v] = d[u] + 1; } } } return d[t] != -1; } int dfs(int u, int flow) { if(u == t) return flow; int res = 0; for (int i = 0;i < table[u].size();++ i) { int v = table[u][i].v; if (table[u][i].cost > 0 && d[v] == d[u] + 1) { int tmp = dfs(v, min(flow, table[u][i].cost)); flow -= tmp; table[u][i].cost -= tmp; res += tmp; for (int j = 0;j < table[v].size();++ j) { if (table[v][j].v == u) { table[v][j].cost += tmp; break; } } if (flow == 0) break; } } if (res == 0) d[u] = -1; return res; } int dinic() { int res = 0; while (bfs()) { res += dfs(s, kInf); } return res; } int main() { int m, a, b; scanf("%d%d", &n, &m); for (int i = 0;i < m;++ i) { scanf("%d%d", &a, &b); table[a].push_back({b + n, 1}); table[b + n].push_back({a, 0}); } s = 0; t = n + n + 1; for (int i = 1;i <= n;++ i) { table[s].push_back({i, 1}); table[i].push_back({s, 0}); table[i + n].push_back({t, 1}); table[t].push_back({i + n, 0}); } printf("%d\n", dinic()); return 0; }