HDU - 6598 Harmonious Army (最小割)
題目鏈接
題意
每個人可以選擇兩種角色(A,B)(A, B)(A,B),給定MMM個關系(x,y)(x, y)(x,y),如果x,yx, yx,y同時選擇AAA總的攻擊力加aaa,如果x,yx, yx,y同時選擇BBB總的攻擊力加ccc,如果x,yx, yx,y分別選擇A,BA,BA,B總的攻擊力加ccc,求如何分配使得總的攻擊力最大?
思路
轉化為最小割模型,統計所有流量,構造使得最小割為多加的流量,邊權擴大2倍,防止小數。
(來自題解)
設一條邊的三種貢獻為 A,B,CA,B,CA,B,C,可以得到以下方程:
a+b=A+Ba + b = A + Ba+b=A+B(x,yx, yx,y 都選 Mage)
c+d=C+Bc + d = C + Bc+d=C+B(x,yx, yx,y 都選 Warrior)
a+d+e=A+Ca + d + e = A + Ca+d+e=A+C(xxx 選 Mage, yyy 選 Warrior )
b+c+e=A+Cb + c + e = A + Cb+c+e=A+C(xxx 選 Warrior, yyy 選 Mage )
可得一組解 a=b=(A+B)/2,c=d=(C+B)/2,e=?B+(A+C)/2a = b =(A + B)/ 2, c = d = (C + B) / 2, e = -B + (A + C) / 2a=b=(A+B)/2,c=d=(C+B)/2,e=?B+(A+C)/2 ,然后將所有有關系的兩點的圖合并,用所有貢獻減掉這個圖的最小割即可。
#include <bits/stdc++.h> #define endl '\n' const int maxn = 5e2 + 5; const int inf = 0x3f3f3f3f; const int mod = 1e9 + 7; using namespace std; struct Dinic{struct ac{int v, c, nex;}edge[maxn << 7]; // 根據題目要求計算int s, e;int head[maxn], dis[maxn], curedge[maxn], cnt;void init() {cnt = 0;memset(head, -1, sizeof(head));}void add(int u, int v, int c) {// 正向建邊edge[cnt] = {v, c, head[u]};head[u] = cnt++;// 反向建邊, 流量為0edge[cnt] = {u, 0, head[v]};head[v] = cnt++;}bool bfs() {queue<int> que;que.push(s);memset(dis, 0, sizeof(dis)); // 對圖進行分層dis[s] = 1;while (!que.empty()) {int u = que.front();que.pop();for (int i = head[u]; i != -1; i = edge[i].nex) {int v = edge[i].v;int c = edge[i].c;// 如果節點v已經分過層或者u->v流量為0, continueif (dis[v] || c == 0) continue;dis[v] = dis[u] + 1; // 對v進行標記并加入隊列que.push(v);}}return dis[e] > 0; // 判斷是否存在增廣路,s是否能到達e}int dfs(int u, int flow) { // 增廣路走到u點的最小流量為flowif (u == e || flow == 0) return flow;// 遍歷u的所有出邊for (int &i = curedge[u]; i != -1; i = edge[i].nex) { // 當前弧優化int v = edge[i].v;int c = edge[i].c;// 判斷能否u->v增廣if (dis[v] != dis[u] + 1 || c == 0) continue;int d = dfs(v, min(flow, c));if (d > 0) { // 找到一條增廣路,修改增廣路上的正反向邊edge[i].c -= d;edge[i^1].c += d;return d;} }dis[u] = -1; // // 炸點優化return 0;}long long dinic() {long long sum = 0, d;while (bfs()) { // 判讀是否存在增廣路for (int i = 0; i <= e; ++i) curedge[i] = head[i]; // copy head數組,在dfs中可以直接得到下一條沒有被增廣過的邊while ((d = dfs(s, inf)) > 0) sum += d; // 多次dfs找增廣路}return sum;} }D; int L[maxn], R[maxn]; int main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, m, s, e;while (scanf("%d %d", &n, &m) != EOF) {D.s = s = 0, D.e = e = n + 1;D.init();int u, v, a, b, c;long long ans = 0;fill(L, L+n+1, 0);fill(R, R+n+1, 0);for (int i = 0; i < m; ++i) {scanf("%d %d %d %d %d", &u, &v, &a, &b, &c);ans += a + b + c;D.add(u, v, a + c - 2*b);D.add(v, u, a + c - 2*b);L[u] += b + c;L[v] += b + c;R[u] += a + b;R[v] += a + b;}for (int i = 1; i <= n; ++i) {D.add(s, i, L[i]);D.add(i, e, R[i]);}ans = ans * 2 - D.dinic();printf("%lld\n", ans / 2);}return 0; } 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的HDU - 6598 Harmonious Army (最小割)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 6704 K-th occu
- 下一篇: git 提交