显然是最小割的经典应用“二者选一”
这里有一个用其他算法不好解决的地方,选择了v,则必须选择所有的u,而对于这个直接建好v指向u的边,容量设为正无穷即可。(即该边不可被割)
源点指向某个知识点,边容量为收益大小,这个点再指向汇点,边容量为损失大小。
对于每个点,要么选(切断与汇点的联系),要么不选(切断与源点的联系),用链接源点的收益和减去最小割就是答案。
最小割的巨大优势是,它可以同时考虑所有点的选择,而得出最优解。
最小割==最大流
最小割:将原图割成只与源点相连和只与汇点相连的两个集合,需要割掉的最小边权和
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 #include<algorithm> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 typedef long long ll; 10 const int MAX_N = 1600; 11 const int MAX_M = 50000; 12 const int INF = 1000000000; 13 struct edge { 14 int v, c, next; 15 } e[MAX_M]; 16 int p[MAX_N], eid; 17 void init() { 18 memset(p, -1, sizeof(p)); 19 eid = 0; 20 } 21 void insert(int u, int v, int c) { 22 e[eid].v = v; 23 e[eid].c = c; 24 e[eid].next = p[u]; 25 p[u] = eid++; 26 } 27 void addedge(int u, int v, int c) { 28 insert(u, v, c); 29 insert(v, u, 0); 30 } 31 int S, T; 32 int d[MAX_N]; 33 bool CountLayer() { 34 memset(d, -1, sizeof(d)); 35 queue<int> q; 36 q.push(S); 37 d[S] = 0; 38 while (!q.empty()) { 39 int u = q.front(); 40 q.pop(); 41 for (int i = p[u]; i != -1; i = e[i].next) { 42 int v = e[i].v; 43 if (e[i].c > 0 && d[v] == -1) { 44 q.push(v); 45 d[v] = d[u] + 1; 46 } 47 } 48 } 49 return (d[T] != -1); 50 } 51 52 ll dfs(int u, int flow) { 53 if (u == T) { 54 return flow; 55 } 56 ll res = 0; 57 for (int i = p[u]; i != -1; i = e[i].next) { 58 int v = e[i].v; 59 if (e[i].c > 0 && d[u] + 1 == d[v]) { 60 ll tmp = dfs(v, min(flow, e[i].c)); 61 flow -= tmp; 62 e[i].c -= tmp; 63 res += tmp; 64 e[i ^ 1].c += tmp; 65 if (flow == 0) { 66 break; 67 } 68 } 69 } 70 if (res == 0) { 71 d[u] = -1; 72 } 73 return res; 74 } 75 76 ll maxflow() { 77 ll res = 0; 78 while (CountLayer()) { 79 res += dfs(S, INF); 80 } 81 return res; 82 } 83 84 int main() 85 { int n; 86 cin>>n; 87 ll x,y,sum=0; 88 S=0,T=n+1; 89 init(); 90 for(int i=1;i<=n;i++) 91 { 92 cin>>x>>y; 93 int res=x-y; 94 if(res>0) addedge(0, i, res),sum+=res; 95 96 else addedge(i, n+1, -res); 97 98 } 99 while(~scanf("%d%d",&x,&y)) 100 { 101 addedge(y, x, INF); 102 } 103 cout<<sum-maxflow()<<endl; 104 105 return 0; 106 }