Petya and Graph
#网络流 #图论 #最小割
题目描述
Petya has a simple graph (that is, a graph without loops or multiple edges) consisting of n n n vertices and m m m edges.
The weight of the i i i-th vertex is a i a_i ai.
The weight of the i i i-th edge is w i w_i wi.
A subgraph of a graph is some set of the graph vertices and some set of the graph edges. The set of edges must meet the condition: both ends of each edge from the set must belong to the chosen set of vertices.
The weight of a subgraph is the sum of the weights of its edges, minus the sum of the weights of its vertices. You need to find the maximum weight of subgraph of given graph. The given graph does not contain loops and multiple edges.
输入格式
The first line contains two numbers n n n and m m m ( 1 ≤ n ≤ 1 0 3 , 0 ≤ m ≤ 1 0 3 1 \le n \le 10^3, 0 \le m \le 10^3 1≤n≤103,0≤m≤103) - the number of vertices and edges in the graph, respectively.
The next line contains n n n integers a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an ( 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1≤ai≤109) - the weights of the vertices of the graph.
The following m m m lines contain edges: the i i i-e edge is defined by a triple of integers v i , u i , w i v_i, u_i, w_i vi,ui,wi ( 1 ≤ v i , u i ≤ n , 1 ≤ w i ≤ 1 0 9 , v i ≠ u i 1 \le v_i, u_i \le n, 1 \le w_i \le 10^9, v_i \neq u_i 1≤vi,ui≤n,1≤wi≤109,vi=ui). This triple means that between the vertices v i v_i vi and u i u_i ui there is an edge of weight w i w_i wi. It is guaranteed that the graph does not contain loops and multiple edges.
输出格式
Print one integer — the maximum weight of the subgraph of the given graph.
样例 #1
样例输入 #1
4 5
1 5 2 2
1 3 4
1 4 4
3 4 5
3 2 2
4 2 2
样例输出 #1
8
解法
解题思路
首先这题边权的贡献是正的,点权的贡献是负的,并且边权的选择依赖与点权选择,其实就是一个最大权闭合子图的模型,如下:
有一堆物品,其中有正有负,其中正物品的选择必须选择负物品,求选择的贡献最大。
1. 1. 1.我们让负的物品连接上汇点 T T T,边权为物品的权重的绝对值,砍掉这条边表示为了选择正物品而不得不选上正物品。
2. 2. 2. 同时,让源点连接一个虚拟点 p p p,边权为物品的权重,砍掉这条边表示不选择这个物品。再让 p p p点连接上这个正物品依赖的所有负物品,权重为 i n f inf inf,表示不能砍掉这几条边。
3. 3. 3.最后,累加上所有的正权,减去最小割就是获得的最大权重了。
回到这道题,实际上我们把边权看为正物品,点权看为负物品,那么建图也是类似的了,比如以下的图:
![[Pasted image 20241014150303.png|400]]
建图后得到这样的图(省略权重):
![[Pasted image 20241014150258.png|500]]
我们跑一遍 D i n i c Dinic Dinic算法,使用边权之和减去最小割就是答案了。
代码
const int N = 5e4 + 10;struct edge {int u, v, c;
};vector<edge>e;
vector<int>h[N];
int d[N], cur[N];
int n, m, S, T,tot;
void add(int u, int v, int c) {e.push_back({ u,v,c });h[u].push_back(e.size()-1);e.push_back({ v, u, 0 });h[v].push_back(e.size() - 1);
}bool bfs() { //对点分层,找增广路memset(d, 0, sizeof d);queue<int>q;q.push(S); d[S] = 1;while (q.size()) {int u = q.front(); q.pop();for (int i = 0; i < h[u].size(); i++) {int j = h[u][i];int v = e[j].v, c = e[j].c;if (d[v] == 0 && c > 0) {d[v] = d[u] + 1;q.push(v);if (v == T)return true;}}}return false;
}int dfs(int u, int mf) { //多路增广if (u == T) return mf;int sum = 0;for (int i = cur[u]; i < h[u].size(); i++) {cur[u] = i; //记住u的当前弧int j = h[u][i];int v = e[j].v, c = e[j].c;if (d[v] == d[u] + 1 && c > 0) {int f = dfs(v, min(c, mf));e[j].c -= f;e[j ^ 1].c += f; //更新残留网sum += f;mf -= f;if (mf == 0)break;}}if (sum == 0)d[u] = 0;return sum;
}int dinic() {int res = 0;while (bfs()) {memset(cur, 0, sizeof cur);res += dfs(S, inf);}return res;
}int a[N];
void solve() {cin >> n >> m;tot = n+1;S = N - 1, T = N - 2;for (int i = 1; i <= n; ++i) {cin >> a[i];add(i, T, a[i]);}int sum = 0;for (int i = 1; i <= m; ++i) {int u, v, w;cin >> u >> v >> w;int p = ++tot;add(S, p, w);add(p, u, inf);add(p, v, inf);sum += w;}int t = dinic();int res = sum - t;std::cout << res << "\n";
}signed main() {ios::sync_with_stdio(0);std::cin.tie(0);std::cout.tie(0);int t = 1;//cin >> t;while (t--) {solve();}
}