luogu P3410
최소 컷에 최대 전력 폐쇄 사진으로 사진 촬영
최대한의 이익을 얻으려면 가능한 총 이익에서 최소 비용을 뺄 수 있습니다.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;
int n, m;
int head[N], ver[M], nex[M], tot;
int deep[N];
int cur[N], S, T;
ll maxflow, edge[M];
void add(int x, int y, int z, bool o = 1){
ver[tot] = y;
edge[tot] = z;
nex[tot] = head[x];
head[x] = tot ++ ;
if(o)add(y, x, 0, 0);
}
bool bfs()
{
memset(deep, 0x3f, sizeof deep);
queue<int>q;
q.push(S), deep[S] = 0, cur[S] = head[S];
while(q.size())
{
int x = q.front();
q.pop();
for(int i = head[x]; ~i; i = nex[i]){
int y = ver[i], z = edge[i];
if(z > 0 && deep[y] == INF){
q.push(y);
deep[y] = deep[x] + 1;
if(y == T)return true;
}
}
}
return false;
}
ll dfs(int x, ll flow)
{
if(x == T)return flow;
ll ans = 0, i, k;
for(i = cur[x]; ~i && flow; i = nex[i]){
cur[x] = i;
int y = ver[i];
ll z = edge[i];
if(edge[i] > 0 && (deep[y] == deep[x] + 1))
{
k = dfs(y, min(flow, z));
if(!k)deep[y] = INF;
edge[i] -= k;
edge[i ^ 1] += k;
ans += k;
flow -= k;
}
}
return ans;
}
void dinic()
{
while(bfs()){
for(int i = 1; i <= n + m + 1; ++ i)
cur[i] = head[i];
maxflow += dfs(S, INF);
}
}
int main()
{
memset(head, -1, sizeof head);
scanf("%d%d", &n, &m);
S = 0, T = n + m + 1;
ll sum = 0;
for(int i = 1; i <= n; ++ i){
int x;
scanf("%d", &x);
sum += x;
add(S, i, x);
while(~scanf("%d", &x) && x){
add(i, x + n, INF);
}
}
for(int i = 1; i <= m; ++ i){
int x;
scanf("%d", &x);
add(i + n, T, x);
}
dinic();
ll ans = sum - maxflow;
printf("%lld\n", ans);
return 0;
}