勤奋的杨老师(二)
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
众所周知,杨老师是一位十分勤奋的老师,他非常的热爱学习。
勤奋的他为自己罗列了一个学习清单,共有n个知识点,他可以有选择的进行学习。
每个知识点都会对应0个或1个或多个先修知识点(只有学会了先修知识点才能学习该知识点),同时每个知识点都有一个智慧值和一个智力消耗值。
杨老师希望在进行过激烈的学习之后,他的收获可以·量化为所有学过的题的智慧值的和与智力消耗值的和的差值。请问,这个值最大是多少?
输入描述:
第一行:一个整数n(n<=500)接下来n行,每行两个整数,代表第i个知识点的智慧值和智力消耗值接下来若干行,每行2个整数u, v,代表u是v的先修知识点。
输出描述:
一行,表示杨老师的收获的最大值
示例1
输入
4 5 1 2 1 1 2 1 2 3 1 2 4 2 1
输出
4
最大权闭合子图。最大权闭合子图的权值等于所有正权点之和减去最小割。
mark一下建图方法。
参考博客:
https://www.cnblogs.com/TreeDream/p/5942354.html,其中着重要注意他是如何证明最大权的。

#include<bits/stdc++.h> #define N 505 #define inf LLONG_MAX/2 using namespace std; typedef struct { int v; long long flow; }ss; ss edg[N*N]; int now_edges=0; vector<int>edges[N]; void addedge(int u,int v,long long flow) { edges[u].push_back(now_edges); edg[now_edges++]=(ss){v,flow}; edges[v].push_back(now_edges); edg[now_edges++]=(ss){u,0}; } int dis[N],S,T; bool bfs() { queue<int>q; memset(dis,0,sizeof(dis)); q.push(S); dis[S]=1; while(!q.empty()) { int now=q.front(); q.pop(); int Size=edges[now].size(); for(int i=0;i<Size;i++) { ss e=edg[edges[now][i]]; if(e.flow>0&&dis[e.v]==0) { dis[e.v]=dis[now]+1; q.push(e.v); } } } if(dis[T]==0)return 0; return 1; } int current[N]; long long dfs(int now,long long maxflow) { if(now==T)return maxflow; int Size=edges[now].size(); for(int i=current[now];i<Size;i++) { current[now]=i; ss &e=edg[edges[now][i]]; if(e.flow>0&&dis[e.v]==dis[now]+1) { long long Flow=dfs(e.v,min(maxflow,e.flow)); if(Flow!=0) { e.flow-=Flow; edg[edges[now][i]^1].flow+=Flow; return Flow; } } } return 0; } long long dinic() { long long ans=0,flow; while(bfs()) { memset(current,0,sizeof(current)); while(flow=dfs(S,inf))ans+=flow; } return ans; } int main() { int n,a,b; scanf("%d",&n); S=n+1; T=n+2; long long tot=0; for(int i=1;i<=n;i++) { scanf("%d %d",&a,&b); if(a>=b)addedge(S,i,a-b),tot+=a-b; else addedge(i,T,b-a); } while(scanf("%d %d",&a,&b)==2)addedge(b,a,inf); printf("%lld ",tot-dinic()); return 0; }